1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
|
#include "platform.h"
/*
* We have to be very careful implementing WordS_quot and WordS_rem using / and %
* because C allows
* "The direction of truncation for / and the sign of the result for % are
* machine-dependent for negative operands, ..." (K&R p. 41) (See also p. 205.)
* On the other hand, the SML Basis library spec is completely nailed down.
* On x86, gcc implements / and % using idiv, which fortunately does have the
* same semantics as the SML Basis library. However, gcc's optimizer sometimes
* takes advantage of the flexibility in the C spec when one of the arguments
* is a constant, producing incorrect results. So, we have two options:
*
* Put them in a separate file, all by themselves, without a static inline, and
* use / and % where we know gcc's optimer can't hurt us.
* OR
* Use inline assembler.
*
* We've gone for the first option because of simplicity, and because
* quot and rem are only used with the C codegen. If you really want
* speed, you could try inline assembler.
*
* To get this working on another architecture, you need to check how gcc
* implements / and %.
*/
#ifndef DEBUG
#define DEBUG FALSE
#endif
#if ! (defined (__i386__) || defined (__ppc__) || defined (__sparc__))
#error check that C {/,%} correctly implement {quot,rem} from the basis library
#endif
#define coerce(f, t) \
t f##_to##t (f x) { \
return (t)x; \
}
#define bothCoerce(from, to) \
coerce (Word##S##from, Word##to) \
coerce (Word##U##from, Word##to)
#define binary(kind, name, op) \
Word##kind Word##kind##_##name (Word##kind w1, Word##kind w2) { \
return w1 op w2; \
}
#define bothBinary(size, name, op) \
binary (S##size, name, op) \
binary (U##size, name, op)
#define compare(kind, name, op) \
Bool Word##kind##_##name (Word##kind w1, Word##kind w2) { \
return w1 op w2; \
}
#define bothCompare(size, name, op) \
compare (S##size, name, op) \
compare (U##size, name, op)
#define unary(kind,name, op) \
Word##kind Word##kind##_##name (Word##kind w) { \
return op w; \
}
#define shift(kind, name, op) \
Word##kind Word##kind##_##name (Word##kind w1, Word w2) { \
return w1 op w2; \
}
#define all(size) \
binary (size, add, +) \
binary (size, andb, &) \
compare (size, equal, ==) \
bothCompare (size, ge, >=) \
bothCompare (size, gt, >) \
bothCompare (size, le, <=) \
shift (size, lshift, <<) \
bothCompare (size, lt, <) \
bothBinary (size, mul, *) \
unary (size, neg, -) \
unary (size, notb, ~) \
binary (size, orb, |) \
bothBinary (size, quot, /) \
bothBinary (size, rem, %) \
Word##size Word##size##_rol (Word##size w1, Word w2) { \
return (w1 >> (size - w2)) | (w1 << w2); \
} \
Word##size Word##size##_ror (Word##size w1, Word w2) { \
return (w1 >> w2) | (w1 << (size - w2)); \
} \
shift (S##size, rshift, >>) \
shift (U##size, rshift, >>) \
binary (size, sub, -) \
binary (size, xorb, ^) \
bothCoerce (size, 64) \
bothCoerce (size, 32) \
bothCoerce (size, 16) \
bothCoerce (size, 8)
all (8)
all (16)
all (32)
all (64)
#undef coerce
#undef bothCoerce
#undef binary
#undef bothBinary
#undef compare
#undef bothCompare
#undef unary
#undef shift
#undef all
|