v2 / vlib / builtin / overflow / overflow.v
494 lines · 460 sloc · 11.22 KB · e5df2d5a9261603c27acafe9dd1bfc845bb6b643
Raw
1module overflow
2
3// Functions for integer arithmetic overflow.
4fn C.__builtin_add_overflow(x any, y any, z voidptr) bool
5fn C.__builtin_sub_overflow(x any, y any, z voidptr) bool
6fn C.__builtin_mul_overflow(x any, y any, z voidptr) bool
7
8// add_i8 computes `x` + `y` for i8 values, and panic if overflow occurs
9@[inline]
10fn add_i8(x i8, y i8) i8 {
11 mut res := i8(0)
12 mut is_overflow := false
13 $if gcc || clang {
14 is_overflow = C.__builtin_add_overflow(x, y, &res)
15 } $else {
16 res64 := i64(x) + i64(y)
17 res = i8(res64)
18 is_overflow = res64 > max_i8 || res64 < min_i8
19 }
20 if is_overflow {
21 panic('attempt to add with overflow(i8(${x}) + i8(${y}))')
22 }
23 return res
24}
25
26// add_u8 computes `x` + `y` for u8 values, and panic if overflow occurs
27@[inline]
28fn add_u8(x u8, y u8) u8 {
29 mut res := u8(0)
30 mut is_overflow := false
31 $if gcc || clang {
32 is_overflow = C.__builtin_add_overflow(x, y, &res)
33 } $else {
34 res = x + y
35 is_overflow = res < x
36 }
37 if is_overflow {
38 panic('attempt to add with overflow(u8(${x}) + u8(${y}))')
39 }
40 return res
41}
42
43// sub_i8 computes `x` - `y` for i8 values, and panic if overflow occurs
44@[inline]
45fn sub_i8(x i8, y i8) i8 {
46 mut res := i8(0)
47 mut is_overflow := false
48 $if gcc || clang {
49 is_overflow = C.__builtin_sub_overflow(x, y, &res)
50 } $else {
51 res64 := i64(x) - i64(y)
52 res = i8(res64)
53 is_overflow = res64 > max_i8 || res64 < min_i8
54 }
55 if is_overflow {
56 panic('attempt to sub with overflow(i8(${x}) - i8(${y}))')
57 }
58 return res
59}
60
61// sub_u8 computes `x` - `y` for u8 values, and panic if overflow occurs
62@[inline]
63fn sub_u8(x u8, y u8) u8 {
64 mut res := u8(0)
65 mut is_overflow := false
66 $if gcc || clang {
67 is_overflow = C.__builtin_sub_overflow(x, y, &res)
68 } $else {
69 res = x - y
70 is_overflow = x < y
71 }
72 if is_overflow {
73 panic('attempt to sub with overflow(u8(${x}) - u8(${y}))')
74 }
75 return res
76}
77
78// mul_i8 computes `x` * `y` for i8 values, and panic if overflow occurs
79@[inline]
80fn mul_i8(x i8, y i8) i8 {
81 mut res := i8(0)
82 mut is_overflow := false
83 $if gcc || clang {
84 is_overflow = C.__builtin_mul_overflow(x, y, &res)
85 } $else {
86 res64 := i64(x) * i64(y)
87 res = i8(res64)
88 is_overflow = res64 > max_i8 || res64 < min_i8
89 }
90 if is_overflow {
91 panic('attempt to mul with overflow(i8(${x}) * i8(${y}))')
92 }
93 return res
94}
95
96// mul_u8 computes `x` * `y` for u8 values, and panic if overflow occurs
97@[inline]
98fn mul_u8(x u8, y u8) u8 {
99 mut res := u8(0)
100 mut is_overflow := false
101 $if gcc || clang {
102 is_overflow = C.__builtin_mul_overflow(x, y, &res)
103 } $else {
104 res64 := u64(x) * u64(y)
105 res = u8(res64)
106 is_overflow = res64 > max_u8
107 }
108 if is_overflow {
109 panic('attempt to mul with overflow(u8(${x}) * u8(${y}))')
110 }
111 return res
112}
113
114// add_i16 computes `x` + `y` for i16 values, and panic if overflow occurs
115@[inline]
116fn add_i16(x i16, y i16) i16 {
117 mut res := i16(0)
118 mut is_overflow := false
119 $if gcc || clang {
120 is_overflow = C.__builtin_add_overflow(x, y, &res)
121 } $else {
122 res64 := i64(x) + i64(y)
123 res = i16(res64)
124 is_overflow = res64 > max_i16 || res64 < min_i16
125 }
126 if is_overflow {
127 panic('attempt to add with overflow(i16(${x}) + i16(${y}))')
128 }
129 return res
130}
131
132// add_u16 computes `x` + `y` for u16 values, and panic if overflow occurs
133@[inline]
134fn add_u16(x u16, y u16) u16 {
135 mut res := u16(0)
136 mut is_overflow := false
137 $if gcc || clang {
138 is_overflow = C.__builtin_add_overflow(x, y, &res)
139 } $else {
140 res = x + y
141 is_overflow = res < x
142 }
143 if is_overflow {
144 panic('attempt to add with overflow(u16(${x}) + u16(${y}))')
145 }
146 return res
147}
148
149// sub_i16 computes `x` - `y` for i16 values, and panic if overflow occurs
150@[inline]
151fn sub_i16(x i16, y i16) i16 {
152 mut res := i16(0)
153 mut is_overflow := false
154 $if gcc || clang {
155 is_overflow = C.__builtin_sub_overflow(x, y, &res)
156 } $else {
157 res64 := i64(x) - i64(y)
158 res = i16(res64)
159 is_overflow = res64 > max_i16 || res64 < min_i16
160 }
161 if is_overflow {
162 panic('attempt to sub with overflow(i16(${x}) - i16(${y}))')
163 }
164 return res
165}
166
167// sub_u16 computes `x` - `y` for u16 values, and panic if overflow occurs
168@[inline]
169fn sub_u16(x u16, y u16) u16 {
170 mut res := u16(0)
171 mut is_overflow := false
172 $if gcc || clang {
173 is_overflow = C.__builtin_sub_overflow(x, y, &res)
174 } $else {
175 res = x - y
176 is_overflow = x < y
177 }
178 if is_overflow {
179 panic('attempt to sub with overflow(u16(${x}) - u16(${y}))')
180 }
181 return res
182}
183
184// mul_i16 computes `x` * `y` for i16 values, and panic if overflow occurs
185@[inline]
186fn mul_i16(x i16, y i16) i16 {
187 mut res := i16(0)
188 mut is_overflow := false
189 $if gcc || clang {
190 is_overflow = C.__builtin_mul_overflow(x, y, &res)
191 } $else {
192 res64 := i64(x) * i64(y)
193 res = i16(res64)
194 is_overflow = res64 > max_i16 || res64 < min_i16
195 }
196 if is_overflow {
197 panic('attempt to mul with overflow(i16(${x}) * i16(${y}))')
198 }
199 return res
200}
201
202// mul_u16 computes `x` * `y` for u16 values, and panic if overflow occurs
203@[inline]
204fn mul_u16(x u16, y u16) u16 {
205 mut res := u16(0)
206 mut is_overflow := false
207 $if gcc || clang {
208 is_overflow = C.__builtin_mul_overflow(x, y, &res)
209 } $else {
210 res64 := u64(x) * u64(y)
211 res = u16(res64)
212 is_overflow = res64 > max_u16
213 }
214 if is_overflow {
215 panic('attempt to mul with overflow(u16(${x}) * u16(${y}))')
216 }
217 return res
218}
219
220// add_i32 computes `x` + `y` for i32 values, and panic if overflow occurs
221@[inline]
222fn add_i32(x i32, y i32) i32 {
223 mut res := i32(0)
224 mut is_overflow := false
225 $if gcc || clang {
226 is_overflow = C.__builtin_add_overflow(x, y, &res)
227 } $else {
228 res64 := i64(x) + i64(y)
229 res = i32(res64)
230 is_overflow = res64 > max_i32 || res64 < min_i32
231 }
232 if is_overflow {
233 panic('attempt to add with overflow(i32(${x}) + i32(${y}))')
234 }
235 return res
236}
237
238// add_u32 computes `x` + `y` for u32 values, and panic if overflow occurs
239@[inline]
240fn add_u32(x u32, y u32) u32 {
241 mut res := u32(0)
242 mut is_overflow := false
243 $if gcc || clang {
244 is_overflow = C.__builtin_add_overflow(x, y, &res)
245 } $else {
246 res = x + y
247 is_overflow = res < x
248 }
249 if is_overflow {
250 panic('attempt to add with overflow(u32(${x}) + u32(${y}))')
251 }
252 return res
253}
254
255// sub_i32 computes `x` - `y` for i32 values, and panic if overflow occurs
256@[inline]
257fn sub_i32(x i32, y i32) i32 {
258 mut res := i32(0)
259 mut is_overflow := false
260 $if gcc || clang {
261 is_overflow = C.__builtin_sub_overflow(x, y, &res)
262 } $else {
263 res64 := i64(x) - i64(y)
264 res = i32(res64)
265 is_overflow = res64 > max_i32 || res64 < min_i32
266 }
267 if is_overflow {
268 panic('attempt to sub with overflow(i32(${x}) - i32(${y}))')
269 }
270 return res
271}
272
273// sub_u32 computes `x` - `y` for u32 values, and panic if overflow occurs
274@[inline]
275fn sub_u32(x u32, y u32) u32 {
276 mut res := u32(0)
277 mut is_overflow := false
278 $if gcc || clang {
279 is_overflow = C.__builtin_sub_overflow(x, y, &res)
280 } $else {
281 res = x - y
282 is_overflow = x < y
283 }
284 if is_overflow {
285 panic('attempt to sub with overflow(u32(${x}) - u32(${y}))')
286 }
287 return res
288}
289
290// mul_i32 computes `x` * `y` for i32 values, and panic if overflow occurs
291@[inline]
292fn mul_i32(x i32, y i32) i32 {
293 mut res := i32(0)
294 mut is_overflow := false
295 $if gcc || clang {
296 is_overflow = C.__builtin_mul_overflow(x, y, &res)
297 } $else {
298 res64 := i64(x) * i64(y)
299 res = i32(res64)
300 is_overflow = res64 > max_i32 || res64 < min_i32
301 }
302 if is_overflow {
303 panic('attempt to mul with overflow(i32(${x}) * i32(${y}))')
304 }
305 return res
306}
307
308// mul_u32 computes `x` * `y` for u32 values, and panic if overflow occurs
309@[inline]
310fn mul_u32(x u32, y u32) u32 {
311 mut res := u32(0)
312 mut is_overflow := false
313 $if gcc || clang {
314 is_overflow = C.__builtin_mul_overflow(x, y, &res)
315 } $else {
316 res64 := u64(x) * u64(y)
317 res = u32(res64)
318 is_overflow = res64 > max_u32
319 }
320 if is_overflow {
321 panic('attempt to mul with overflow(u32(${x}) * u32(${y}))')
322 }
323 return res
324}
325
326// add_i64 computes `x` + `y` for i64 values, and panic if overflow occurs
327@[inline]
328fn add_i64(x i64, y i64) i64 {
329 mut res := i64(0)
330 mut is_overflow := false
331 $if gcc || clang {
332 is_overflow = C.__builtin_add_overflow(x, y, &res)
333 } $else {
334 res = x + y
335 is_overflow = (x > 0 && y > 0 && res < 0) || (x < 0 && y < 0 && res > 0)
336 }
337 if is_overflow {
338 panic('attempt to add with overflow(i64(${x}) + i64(${y}))')
339 }
340 return res
341}
342
343// add_u64 computes `x` + `y` for u64 values, and panic if overflow occurs
344@[inline]
345fn add_u64(x u64, y u64) u64 {
346 mut res := u64(0)
347 mut is_overflow := false
348 $if gcc || clang {
349 is_overflow = C.__builtin_add_overflow(x, y, &res)
350 } $else {
351 res = x + y
352 is_overflow = res < x
353 }
354 if is_overflow {
355 panic('attempt to add with overflow(u64(${x}) + u64(${y}))')
356 }
357 return res
358}
359
360// sub_i64 computes `x` - `y` for i64 values, and panic if overflow occurs
361@[inline]
362fn sub_i64(x i64, y i64) i64 {
363 mut res := i64(0)
364 mut is_overflow := false
365 $if gcc || clang {
366 is_overflow = C.__builtin_sub_overflow(x, y, &res)
367 } $else {
368 res = x - y
369 is_overflow = (x >= 0 && y < 0 && res < 0) || (x < 0 && y > 0 && res > 0)
370 }
371 if is_overflow {
372 panic('attempt to sub with overflow(i64(${x}) - i64(${y}))')
373 }
374 return res
375}
376
377// sub_u64 computes `x` - `y` for u64 values, and panic if overflow occurs
378@[inline]
379fn sub_u64(x u64, y u64) u64 {
380 mut res := u64(0)
381 mut is_overflow := false
382 $if gcc || clang {
383 is_overflow = C.__builtin_sub_overflow(x, y, &res)
384 } $else {
385 res = x - y
386 is_overflow = x < y
387 }
388 if is_overflow {
389 panic('attempt to sub with overflow(u64(${x}) - u64(${y}))')
390 }
391 return res
392}
393
394// mul_i64 computes `x` * `y` for i64 values, and panic if overflow occurs
395@[inline]
396fn mul_i64(x i64, y i64) i64 {
397 mut res := i64(0)
398 mut is_overflow := false
399 $if gcc || clang {
400 is_overflow = C.__builtin_mul_overflow(x, y, &res)
401 } $else {
402 res = x * y
403 if x == 0 || y == 0 {
404 is_overflow = false
405 } else if x == min_i64 {
406 is_overflow = y != 1
407 } else if y == min_i64 {
408 is_overflow = x != 1
409 } else {
410 if x > 0 {
411 if y > 0 {
412 is_overflow = x > max_i64 / y
413 } else {
414 is_overflow = y < min_i64 / x
415 }
416 } else if x < 0 {
417 if y > 0 {
418 is_overflow = x < min_i64 / y
419 } else {
420 is_overflow = y < max_i64 / x
421 }
422 }
423 }
424 }
425 if is_overflow {
426 panic('attempt to mul with overflow(i64(${x}) * i64(${y}))')
427 }
428 return res
429}
430
431// mul_u64 computes `x` * `y` for u64 values, and panic if overflow occurs
432@[inline]
433fn mul_u64(x u64, y u64) u64 {
434 mut res := u64(0)
435 mut is_overflow := false
436 $if gcc || clang {
437 is_overflow = C.__builtin_mul_overflow(x, y, &res)
438 } $else {
439 res = x * y
440 is_overflow = y != 0 && x > max_u64 / y
441 }
442 if is_overflow {
443 panic('attempt to mul with overflow(u64(${x}) * u64(${y}))')
444 }
445 return res
446}
447
448/////////////////////////////////////////////////////////////////////////////////////////////
449// These are here to prevent cgen errors for `./v -check-overflow vlib/math/vec/vec4_test.v`
450// TODO: check for correctness and add tests. Improve markused so it keeps them, when they are used.
451@[inline; markused]
452fn add_int(x int, y int) int {
453 return add_i32(x, y)
454}
455
456@[inline; markused]
457fn sub_int(x int, y int) int {
458 return sub_i32(x, y)
459}
460
461@[inline; markused]
462fn mul_int(x int, y int) int {
463 return mul_i32(x, y)
464}
465
466@[inline; markused]
467fn add_f32(x f32, y f32) f32 {
468 return x + y
469}
470
471@[inline; markused]
472fn sub_f32(x f32, y f32) f32 {
473 return x - y
474}
475
476@[inline; markused]
477fn mul_f32(x f32, y f32) f32 {
478 return x * y
479}
480
481@[inline; markused]
482fn add_f64(x f64, y f64) f64 {
483 return x + y
484}
485
486@[inline; markused]
487fn sub_f64(x f64, y f64) f64 {
488 return x - y
489}
490
491@[inline; markused]
492fn mul_f64(x f64, y f64) f64 {
493 return x * y
494}
495