From 72a8824940eb6d26bd30ce91c6056bca8d4c1a16 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 22 Jan 2009 16:51:54 +0000 Subject: [PATCH] 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. --- rangetest.c | 2 +- support/tock_support.h | 23 ++++++++++++++++++++--- testcases/time-mul.occ | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 testcases/time-mul.occ diff --git a/rangetest.c b/rangetest.c index cdd4e5d..8c87f14 100644 --- a/rangetest.c +++ b/rangetest.c @@ -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) diff --git a/support/tock_support.h b/support/tock_support.h index d9305ba..7603fb7 100644 --- a/support/tock_support.h +++ b/support/tock_support.h @@ -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) diff --git a/testcases/time-mul.occ b/testcases/time-mul.occ new file mode 100644 index 0000000..a730d02 --- /dev/null +++ b/testcases/time-mul.occ @@ -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) +: