diff --git a/llrtc/Makefile b/llrtc/Makefile index c271d0e..bde100e 100644 --- a/llrtc/Makefile +++ b/llrtc/Makefile @@ -1,21 +1,22 @@ -DIRECTORIES = divmod - all: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir; \ - done + make -C lib + +ir: + make -C lib ir test: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir test; \ - done + make -C lib test clean-test: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir clean-test; \ - done + make -C lib clean-test + +clean-temp: + make -C lib clean-temp clean: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir clean; \ - done \ No newline at end of file + make -C lib clean + +install: ir + make -C lib clean-test + make -C lib clean-temp + \ No newline at end of file diff --git a/llrtc/common.mk b/llrtc/common.mk deleted file mode 100644 index 3de9c12..0000000 --- a/llrtc/common.mk +++ /dev/null @@ -1,26 +0,0 @@ -CLANG = clang -CF = -Wall -ansi -OUTDIR = .. - -all: ir - -$(OUTPUT).c: $(OUTPUT).h - -$(OUTPUT): test.c $(OUTPUT).c - $(CLANG) $(CF) -ftrapv -o $@ $+ - -test: $(OUTPUT) - python test.py - -ir: - CLANG -m32 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86/$(OUTPUT).ll - CLANG -m64 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86_64/$(OUTPUT).ll - python ../tools/striptriple.py $(OUTDIR)/x86/$(OUTPUT).ll - python ../tools/striptriple.py $(OUTDIR)/x86_64/$(OUTPUT).ll - -clean-test: - rm -f $(OUTPUT) - -clean: clean-test - rm -f $(OUTDIR)/x86/$(OUTPUT).ll - rm -f $(OUTDIR)/x86_64/$(OUTPUT).ll diff --git a/llrtc/lib/.gitignore b/llrtc/lib/.gitignore new file mode 100644 index 0000000..fbcf76a --- /dev/null +++ b/llrtc/lib/.gitignore @@ -0,0 +1,4 @@ +*.o +*.run +*.out +*.ll diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile index 1bb325f..8c9361d 100644 --- a/llrtc/lib/Makefile +++ b/llrtc/lib/Makefile @@ -1,44 +1,66 @@ OUTPUT = llrt -SOURCES = udivmod64.c +SOURCES = udivmod64.c sdivmod64.c +TESTS = test_udivmod64.c test_sdivmod64.c CLANG = clang +LLVM_LINK = llvm-link CF = -Wall -ansi CF_TEST = $(CF) -ftrapv CF_BUILD = $(CF) -O0 -emit-llvm OUTDIR = .. +STRIPPER = ../tools/striptriple.py all: ir -ir: $(SOURCES) - $(CLANG) -m32 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86.ll -c $(SOURCES) - python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86.ll - $(CLANG) -m64 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86_64.ll -c $(SOURCES) - python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86_64.ll +ir: $(OUTDIR)/$(OUTPUT)_x86.ll $(OUTDIR)/$(OUTPUT)_x86_64.ll -lib$(OUTPUT).a: $(SOURCES) - $(CLANG) $(CF) -o $@ -c $+ +$(OUTDIR)/$(OUTPUT)_x86.ll: $(SOURCES:.c=_x86.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ -build-test: lib$(OUTPUT).a - for src in $(SOURCES); do \ - $(CLANG) $(CF_TEST) -o test_$${src%.*} test_$$src -L. -lllrt; \ - done; +$(OUTDIR)/$(OUTPUT)_x86_64.ll: $(SOURCES:.c=_x86_64.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ -test: build-test - for src in $(SOURCES); do \ - echo "testing $${src%.*}"; \ - python test_$${src%.*}.py > test_$${src%.*}.out; \ +build-test: $(SOURCES:.c=.o) $(TESTS:.c=.run) + +lib$(OUTPUT).a: $(SOURCES:.c=.o) + $(CLANG) -static $+ -o $@ + +test: $(TESTS:.c=.run) + for src in $+; do \ + echo "testing $${src}"; \ + python $${src%.*}.py > $${src%.*}.out; \ done; clean-test: rm -f *.out - rm -f *.a - for src in $(SOURCES); do \ - rm -f test_$${src%.*} ;\ - done; + rm -f *.o + rm -f *.run -clean-dist: - rm $(OUTDIR)/*.ll +clean-dist: clean-temp + rm -f *.ll + +clean-temp: + rm -f *.bc + rm -f *.o + rm -f *.out clean: clean-test clean-dist -udivmod64.c: udivmod64.h +%.c: llrt.h + +%_x86.bc: %.c + $(CLANG) -m32 $(CF_BUILD) -c $< -o $@ + +%_x86_64.bc: %.c + $(CLANG) -m64 $(CF_BUILD) -c $< -o $@ + +%.o: %.c + $(CLANG) $(CF_TEST) -c $< + +%.run: %.c + $(CLANG) $(CF_TEST) -o $@ $+ + +test_udivmod64.run: udivmod64.o +test_sdivmod64.run: udivmod64.o sdivmod64.o diff --git a/llrtc/lib/udivmod64.h b/llrtc/lib/llrt.h similarity index 50% rename from llrtc/lib/udivmod64.h rename to llrtc/lib/llrt.h index 9cbcd8c..0d26309 100644 --- a/llrtc/lib/udivmod64.h +++ b/llrtc/lib/llrt.h @@ -1,11 +1,12 @@ -#ifndef LLRT_UDIVMOD_H_ -#define LLRT_UDIVMOD_H_ +#ifndef LLRT_H_ +#define LLRT_H_ #include #define BITS_PER_BYTE 8 uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); +int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder); -#endif /* LLRT_UDIVMOD_H_ */ +#endif /* LLRT_H_ */ diff --git a/llrtc/lib/sdivmod64.c b/llrtc/lib/sdivmod64.c new file mode 100644 index 0000000..df294b3 --- /dev/null +++ b/llrtc/lib/sdivmod64.c @@ -0,0 +1,40 @@ +#include "llrt.h" +#include + +/* +Calls to udivmod64 internally. +Note: remainder uses sign of divisor. +*/ +int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder) +{ + int signbitidx = BITS_PER_BYTE * sizeof(dividend) - 1; + int signed_dividend = dividend < 0; + int signed_divisor = divisor < 0; + int signed_result = signed_divisor ^ signed_dividend; + + int64_t quotient; + uint64_t udvd, udvr, uquotient, uremainder; + + udvd = signed_dividend ? -dividend : dividend; + udvr = signed_divisor ? -divisor : divisor; + uquotient = udivmod64(udvd, udvr, &uremainder); + + if (signed_result){ + if (uremainder) { + quotient = -(int64_t)uquotient - 1; + } else { + quotient = -(int64_t)uquotient; + } + if (remainder) { + /* if signed, there could be unsigned overflow + causing undefined behavior */ + *remainder = (uint64_t)dividend - (uint64_t)quotient * (uint64_t)divisor; + } + } else { + quotient = (int64_t)uquotient; + if (remainder) { + *remainder = signed_divisor ? -uremainder : uremainder; + } + } + return quotient; +} diff --git a/llrtc/lib/test_sdivmod64.c b/llrtc/lib/test_sdivmod64.c new file mode 100644 index 0000000..1e804d6 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.c @@ -0,0 +1,21 @@ +#include +#include +#include "llrt.h" + +int main(int argc, char * argv[]){ + int64_t n, d, q, r; + + if (argc != 3) { + printf("invalid argument: %s dividend divisor", argv[0]); + return 1; + } + sscanf(argv[1], "%lld", &n); + sscanf(argv[2], "%lld", &d); + + q = sdivmod64(n, d, &r); + + printf("%lld\n", q); + printf("%lld\n", r); + + return 0; +} diff --git a/llrtc/lib/test_sdivmod64.py b/llrtc/lib/test_sdivmod64.py new file mode 100644 index 0000000..4aa49a9 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.py @@ -0,0 +1,56 @@ +import math +import os +import subprocess +udt = os.path.join('.', 'test_sdivmod64.run') + +def testcase(dividend, divisor): + print 'divmod64(%d, %d)' % (dividend, divisor) + + procargs = ('%s %s %s' % (udt, dividend, divisor)).split() + result = subprocess.check_output(procargs) + gotQ, gotR = map(int, result.splitlines()) + + expectQ = dividend // divisor + expectR = dividend % divisor + + print 'Q = %d, R = %d' % (gotQ, gotR) + + if expectQ != gotQ: + raise ValueError("invalid quotient: got=%d but expect=%d" % + (gotQ, expectQ)) + if expectR != gotR: + raise ValueError("invalid remainder: got=%d but expect=%d" % + (gotR, expectR)) + print 'OK' + +def testsequence(): + subjects = [ + (0, 1), + (0, 0xffffffff), + (1, 2), + (1, 983219), + (2, 2), + (3, 2), + (1024, 2), + (2048, 512), + (21321, 512), + (9329189, 1031), + (0xffffffff, 2), + (0xffffffff, 0xffff), + (0x1ffffffff, 2), + (0x1ffffffff, 0xffff), + (0xffff, 0xffffffff), + (0x0fffffffffffffff, 0xffff), + (0x7fffffffffffffff, 0x7fffffffffffffff), + (0x7fffffffffffffff, 0x7ffffffffffffff0), + (0x7fffffffffffffff, 87655678587161901), + ] + + for dvd, dvr in subjects: + testcase(dvd, dvr) + testcase(dvd, -dvr) + testcase(-dvd, dvr) + testcase(-dvd, -dvr) + +if __name__ == '__main__': + testsequence() diff --git a/llrtc/lib/test_udivmod64.c b/llrtc/lib/test_udivmod64.c index e2935c5..70b44aa 100644 --- a/llrtc/lib/test_udivmod64.c +++ b/llrtc/lib/test_udivmod64.c @@ -1,8 +1,6 @@ #include #include - -extern uint64_t -udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); +#include "llrt.h" int main(int argc, char * argv[]){ uint64_t n, d, q, r; @@ -19,4 +17,4 @@ int main(int argc, char * argv[]){ printf("%llu\n", r); return 0; -} \ No newline at end of file +} diff --git a/llrtc/lib/test_udivmod64.py b/llrtc/lib/test_udivmod64.py index 487a458..da07ccb 100644 --- a/llrtc/lib/test_udivmod64.py +++ b/llrtc/lib/test_udivmod64.py @@ -1,7 +1,7 @@ import math import os import subprocess -udt = os.path.join('.', 'test_udivmod64') +udt = os.path.join('.', 'test_udivmod64.run') def testcase(dividend, divisor): print 'divmod64(%d, %d)' % (dividend, divisor) diff --git a/llrtc/lib/udivmod64.c b/llrtc/lib/udivmod64.c index a028aea..5936f98 100644 --- a/llrtc/lib/udivmod64.c +++ b/llrtc/lib/udivmod64.c @@ -2,7 +2,7 @@ Implements unsigned divmod using for platform missing 64-bit division and/or modulo functions. */ -#include "udivmod64.h" +#include "llrt.h" /* count left zero for 64-bit words @@ -79,6 +79,6 @@ uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder) quotient |= 1ull << (63 - i); } } - *remainder = state.tmp; + if (remainder) *remainder = state.tmp; return quotient; }