Had a go at implementing multiply overflow checking (with a single division, and pre-checks)

I also added an occam testcase to help time the different between * and TIMES.  But gcc optimises out the loop with TIMES under -O2, and with -O0 there is a factor of four difference.
This commit is contained in:
Neil Brown 2009-01-22 16:51:54 +00:00
parent c9fa0f774c
commit 72a8824940
3 changed files with 59 additions and 4 deletions

View File

@ -13,7 +13,7 @@ int g_stopped;
passes++; \
} else { \
failures++; \
report_failure(#call " failed, expected to stop\n"); \
report_failure(#call " failed, expected to stop, got: %lld\n", (int64_t)call); \
} \
} while(0)

View File

@ -143,8 +143,25 @@ static inline int occam_check_retype (int src, int dest, const char *pos) {
#define MAKE_MUL(type) \
static inline type occam_mul_##type (type, type, const char *) occam_unused; \
static inline type occam_mul_##type (type a, type b, const char *pos) { \
return a * b; /*TODO*/ \
if (( (a < 0 ? -a : a) >> ((sizeof(type)*CHAR_BIT/2)-1) \
| (b < 0 ? -b : b) >> ((sizeof(type)*CHAR_BIT/2)-1)) == 0) { \
/*overflow not possible on such small numbers*/ \
return a * b; \
} else if (b == 0) { \
return 0; \
} else { \
const type r = a * b; \
/* Taken from: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg326431.html */ \
if (r / b != a) { \
occam_stop(pos, 3, "integer overflow when doing %d * %d", a, b); \
} else { \
return r; \
} \
} \
}
#define MAKE_MULF(type) \
static inline type occam_mul_##type (type, type, const char *) occam_unused; \
static inline type occam_mul_##type (type a, type b, const char *pos) { return a * b;}
#define MAKE_DIV(type) \
static inline type occam_div_##type (type, type, const char *) occam_unused; \
static inline type occam_div_##type (type a, type b, const char *pos) { \
@ -295,7 +312,7 @@ MAKE_ALL_SIGNED(int64_t, "%lld", uint64_t)
MAKE_RANGE_CHECK(float, "%f")
MAKE_ADDF(float)
MAKE_SUBTRF(float)
MAKE_MUL(float)
MAKE_MULF(float)
MAKE_DIVF(float)
MAKE_NEGATEF(float)
MAKE_DUMB_REM(float)
@ -304,7 +321,7 @@ MAKE_DUMB_REM(float)
MAKE_RANGE_CHECK(double, "%f")
MAKE_ADDF(double)
MAKE_SUBTRF(double)
MAKE_MUL(double)
MAKE_MULF(double)
MAKE_DIVF(double)
MAKE_NEGATEF(double)
MAKE_DUMB_REM(double)

38
testcases/time-mul.occ Normal file
View File

@ -0,0 +1,38 @@
#INCLUDE "course.occ"
PROC main(CHAN OF BYTE out)
TIMER t:
INT t0, t1, x:
SEQ
t ? t0
SEQ i = 0 FOR 100000
x := i * 5
t ? t1
t1 := t1 - t0
out.string("Time for low numbers MUL: ", 0, out)
out.int(t1, 0, out)
t ? t0
SEQ i = 0 FOR 100000
x := i TIMES 5
t ? t1
t1 := t1 - t0
out.string("Time for low numbers TIMES: ", 0, out)
out.int(t1, 0, out)
t ? t0
SEQ i = 100000000 FOR 100000
x := i * 5
t ? t1
t1 := t1 - t0
out.string("Time for high numbers MUL: ", 0, out)
out.int(t1, 0, out)
t ? t0
SEQ i = 100000000 FOR 100000
x := i TIMES 5
t ? t1
t1 := t1 - t0
out.string("Time for high numbers TIMES: ", 0, out)
out.int(t1, 0, out)
: