begin low-level runtime implementation

This commit is contained in:
Siu Kwan Lam 2013-08-13 18:38:41 -05:00
commit 07c64779d8
9 changed files with 301 additions and 0 deletions

21
llrtc/Makefile Normal file
View file

@ -0,0 +1,21 @@
DIRECTORIES = divmod
all:
for mydir in $(DIRECTORIES); do \
make -C $$mydir; \
done
test:
for mydir in $(DIRECTORIES); do \
make -C $$mydir test; \
done
clean-test:
for mydir in $(DIRECTORIES); do \
make -C $$mydir clean-test; \
done
clean:
for mydir in $(DIRECTORIES); do \
make -C $$mydir clean; \
done

25
llrtc/README.md Normal file
View file

@ -0,0 +1,25 @@
# LLRT: Low Level Runtime
## Why?
The same reason for LLVM compiler-rt. LLVM generates libgcc symbols, such as
__divdi3 for 64-bit division on 32-bit platform. They are not also available.
We need to ship compiler-rt but it is not Windows ready.
This subproject aims to provide a small portable subset of compiler-rt.
Start small and add only the things we really needed.
Performance is not crucial but should not be terrible.
Functionality and usefullness should be more important than performance.
## Developer Instructions
LLRT implements some functionalities in compiler-rt in ANSI C.
The C files are compiled using clang to produce LLVM IR which are shipped.
The IR files are committed in the repository.
So, remember to build the IR files commit them after modifying the C files.
## Build Requirement
- Make
- Clang
- Python

26
llrtc/common.mk Normal file
View file

@ -0,0 +1,26 @@
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

44
llrtc/lib/Makefile Normal file
View file

@ -0,0 +1,44 @@
OUTPUT = llrt
SOURCES = udivmod64.c
CLANG = clang
CF = -Wall -ansi
CF_TEST = $(CF) -ftrapv
CF_BUILD = $(CF) -O0 -emit-llvm
OUTDIR = ..
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
lib$(OUTPUT).a: $(SOURCES)
$(CLANG) $(CF) -o $@ -c $+
build-test: lib$(OUTPUT).a
for src in $(SOURCES); do \
$(CLANG) $(CF_TEST) -o test_$${src%.*} test_$$src -L. -lllrt; \
done;
test: build-test
for src in $(SOURCES); do \
echo "testing $${src%.*}"; \
python test_$${src%.*}.py > test_$${src%.*}.out; \
done;
clean-test:
rm -f *.out
rm -f *.a
for src in $(SOURCES); do \
rm -f test_$${src%.*} ;\
done;
clean-dist:
rm $(OUTDIR)/*.ll
clean: clean-test clean-dist
udivmod64.c: udivmod64.h

View file

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdint.h>
extern uint64_t
udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder);
int main(int argc, char * argv[]){
uint64_t n, d, q, r;
if (argc != 3) {
printf("invalid argument: %s dividend divisor", argv[0]);
return 1;
}
sscanf(argv[1], "%llu", &n);
sscanf(argv[2], "%llu", &d);
q = udivmod64(n, d, &r);
printf("%llu\n", q);
printf("%llu\n", r);
return 0;
}

View file

@ -0,0 +1,53 @@
import math
import os
import subprocess
udt = os.path.join('.', 'test_udivmod64')
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, 0xffffffffffffffff),
(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),
(0xffffffffffffffff, 0xffff),
(0xffffffffffffffff, 0x7fffffffffffffff),
(0xffffffffffffffff, 0xfffffffffffffff0),
(0xffffffffffffffff, 87655678587161901),
]
for dvd, dvr in subjects:
testcase(dvd, dvr)
if __name__ == '__main__':
testsequence()

84
llrtc/lib/udivmod64.c Normal file
View file

@ -0,0 +1,84 @@
/*
Implements unsigned divmod using for platform missing 64-bit division and/or
modulo functions.
*/
#include "udivmod64.h"
/*
count left zero for 64-bit words
*/
static
int clz64(uint64_t x)
{
const int total_bits = sizeof(x) * BITS_PER_BYTE;
int zc = 0;
while (zc < total_bits && ((x >> (total_bits - zc - 1)) & 1) == 0) {
++zc;
}
return zc;
}
typedef struct div_state_
{
uint64_t tmp, dvd;
} div_state;
/*
Left shift div_state by 1 bit
*/
static
void div_state_lshift(div_state *state)
{
state->tmp = (state->tmp << 1) | (state->dvd >> 63);
state->dvd = state->dvd << 1;
}
/*
Division of unsigned 64-bit word using 64-bit addition and subtration following
the shift-restore division algorithm.
For those interested in 32-bit implementation,
mapping of 64-bit addition and subtraction to 32-bit should be trivial.
Reference:
- IBM. The PowerPC Compiler Writer's Guide
- LLVM compiler-rt
Assumptions:
- all operands and results are positive
- unsigned wrapped around
*/
uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder)
{
div_state state = {0, dividend};
uint64_t quotient = 0;
int i;
int skipahead;
if (divisor == 0) {
return 1 / 0; /* intentionally div by zero */
}
/*
skipahead to reduce iteration
*/
skipahead = clz64(dividend);
for (i = 0; i < skipahead; ++i) {
div_state_lshift(&state);
}
/*
division loop
*/
for (i = skipahead; i < 64; ++i) {
div_state_lshift(&state);
if (state.tmp >= divisor) {
state.tmp = state.tmp - divisor;
quotient |= 1ull << (63 - i);
}
}
*remainder = state.tmp;
return quotient;
}

11
llrtc/lib/udivmod64.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef LLRT_UDIVMOD_H_
#define LLRT_UDIVMOD_H_
#include <stdint.h>
#define BITS_PER_BYTE 8
uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder);
#endif /* LLRT_UDIVMOD_H_ */

View file

@ -0,0 +1,15 @@
import sys
import re
buf = []
with open(sys.argv[1], 'r') as fin:
tripleline = re.compile('^target\s+triple\s+=\s+')
for line in fin.readlines():
if not tripleline.match(line):
buf.append(line)
with open(sys.argv[1], 'w') as fout:
for line in buf:
fout.write(line)