add sdivmod;
improve build system;
This commit is contained in:
parent
07c64779d8
commit
8480d55faf
11 changed files with 190 additions and 73 deletions
|
|
@ -1,21 +1,22 @@
|
||||||
DIRECTORIES = divmod
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
for mydir in $(DIRECTORIES); do \
|
make -C lib
|
||||||
make -C $$mydir; \
|
|
||||||
done
|
ir:
|
||||||
|
make -C lib ir
|
||||||
|
|
||||||
test:
|
test:
|
||||||
for mydir in $(DIRECTORIES); do \
|
make -C lib test
|
||||||
make -C $$mydir test; \
|
|
||||||
done
|
|
||||||
|
|
||||||
clean-test:
|
clean-test:
|
||||||
for mydir in $(DIRECTORIES); do \
|
make -C lib clean-test
|
||||||
make -C $$mydir clean-test; \
|
|
||||||
done
|
clean-temp:
|
||||||
|
make -C lib clean-temp
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
for mydir in $(DIRECTORIES); do \
|
make -C lib clean
|
||||||
make -C $$mydir clean; \
|
|
||||||
done
|
install: ir
|
||||||
|
make -C lib clean-test
|
||||||
|
make -C lib clean-temp
|
||||||
|
|
||||||
|
|
@ -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
|
|
||||||
4
llrtc/lib/.gitignore
vendored
Normal file
4
llrtc/lib/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.o
|
||||||
|
*.run
|
||||||
|
*.out
|
||||||
|
*.ll
|
||||||
|
|
@ -1,44 +1,66 @@
|
||||||
OUTPUT = llrt
|
OUTPUT = llrt
|
||||||
SOURCES = udivmod64.c
|
SOURCES = udivmod64.c sdivmod64.c
|
||||||
|
TESTS = test_udivmod64.c test_sdivmod64.c
|
||||||
|
|
||||||
CLANG = clang
|
CLANG = clang
|
||||||
|
LLVM_LINK = llvm-link
|
||||||
CF = -Wall -ansi
|
CF = -Wall -ansi
|
||||||
CF_TEST = $(CF) -ftrapv
|
CF_TEST = $(CF) -ftrapv
|
||||||
CF_BUILD = $(CF) -O0 -emit-llvm
|
CF_BUILD = $(CF) -O0 -emit-llvm
|
||||||
OUTDIR = ..
|
OUTDIR = ..
|
||||||
|
STRIPPER = ../tools/striptriple.py
|
||||||
|
|
||||||
all: ir
|
all: ir
|
||||||
|
|
||||||
ir: $(SOURCES)
|
ir: $(OUTDIR)/$(OUTPUT)_x86.ll $(OUTDIR)/$(OUTPUT)_x86_64.ll
|
||||||
$(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
|
|
||||||
|
|
||||||
lib$(OUTPUT).a: $(SOURCES)
|
$(OUTDIR)/$(OUTPUT)_x86.ll: $(SOURCES:.c=_x86.bc)
|
||||||
$(CLANG) $(CF) -o $@ -c $+
|
$(LLVM_LINK) -S $+ -o $@
|
||||||
|
python $(STRIPPER) $@
|
||||||
|
|
||||||
build-test: lib$(OUTPUT).a
|
$(OUTDIR)/$(OUTPUT)_x86_64.ll: $(SOURCES:.c=_x86_64.bc)
|
||||||
for src in $(SOURCES); do \
|
$(LLVM_LINK) -S $+ -o $@
|
||||||
$(CLANG) $(CF_TEST) -o test_$${src%.*} test_$$src -L. -lllrt; \
|
python $(STRIPPER) $@
|
||||||
done;
|
|
||||||
|
|
||||||
test: build-test
|
build-test: $(SOURCES:.c=.o) $(TESTS:.c=.run)
|
||||||
for src in $(SOURCES); do \
|
|
||||||
echo "testing $${src%.*}"; \
|
lib$(OUTPUT).a: $(SOURCES:.c=.o)
|
||||||
python test_$${src%.*}.py > test_$${src%.*}.out; \
|
$(CLANG) -static $+ -o $@
|
||||||
|
|
||||||
|
test: $(TESTS:.c=.run)
|
||||||
|
for src in $+; do \
|
||||||
|
echo "testing $${src}"; \
|
||||||
|
python $${src%.*}.py > $${src%.*}.out; \
|
||||||
done;
|
done;
|
||||||
|
|
||||||
clean-test:
|
clean-test:
|
||||||
rm -f *.out
|
rm -f *.out
|
||||||
rm -f *.a
|
rm -f *.o
|
||||||
for src in $(SOURCES); do \
|
rm -f *.run
|
||||||
rm -f test_$${src%.*} ;\
|
|
||||||
done;
|
|
||||||
|
|
||||||
clean-dist:
|
clean-dist: clean-temp
|
||||||
rm $(OUTDIR)/*.ll
|
rm -f *.ll
|
||||||
|
|
||||||
|
clean-temp:
|
||||||
|
rm -f *.bc
|
||||||
|
rm -f *.o
|
||||||
|
rm -f *.out
|
||||||
|
|
||||||
clean: clean-test clean-dist
|
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
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
#ifndef LLRT_UDIVMOD_H_
|
#ifndef LLRT_H_
|
||||||
#define LLRT_UDIVMOD_H_
|
#define LLRT_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define BITS_PER_BYTE 8
|
#define BITS_PER_BYTE 8
|
||||||
|
|
||||||
uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder);
|
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_ */
|
||||||
|
|
||||||
40
llrtc/lib/sdivmod64.c
Normal file
40
llrtc/lib/sdivmod64.c
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include "llrt.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
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;
|
||||||
|
}
|
||||||
21
llrtc/lib/test_sdivmod64.c
Normal file
21
llrtc/lib/test_sdivmod64.c
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
56
llrtc/lib/test_sdivmod64.py
Normal file
56
llrtc/lib/test_sdivmod64.py
Normal file
|
|
@ -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()
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "llrt.h"
|
||||||
extern uint64_t
|
|
||||||
udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder);
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]){
|
int main(int argc, char * argv[]){
|
||||||
uint64_t n, d, q, r;
|
uint64_t n, d, q, r;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
udt = os.path.join('.', 'test_udivmod64')
|
udt = os.path.join('.', 'test_udivmod64.run')
|
||||||
|
|
||||||
def testcase(dividend, divisor):
|
def testcase(dividend, divisor):
|
||||||
print 'divmod64(%d, %d)' % (dividend, divisor)
|
print 'divmod64(%d, %d)' % (dividend, divisor)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
Implements unsigned divmod using for platform missing 64-bit division and/or
|
Implements unsigned divmod using for platform missing 64-bit division and/or
|
||||||
modulo functions.
|
modulo functions.
|
||||||
*/
|
*/
|
||||||
#include "udivmod64.h"
|
#include "llrt.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
count left zero for 64-bit words
|
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);
|
quotient |= 1ull << (63 - i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*remainder = state.tmp;
|
if (remainder) *remainder = state.tmp;
|
||||||
return quotient;
|
return quotient;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue