Compare commits
12 Commits
master
...
start-llvm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac516d55a2 | ||
|
|
68611b4df3 | ||
|
|
49e1bf204f | ||
|
|
5369c15e05 | ||
|
|
a282292604 | ||
|
|
1be24ef771 | ||
|
|
449a89d6b3 | ||
|
|
c9029b1216 | ||
|
|
1671ce2285 | ||
|
|
098ab080ca | ||
|
|
cfae563aef | ||
|
|
8502abeff6 |
@ -409,6 +409,7 @@ def emitheader():
|
||||
emitln(" if os.environ.get('TRACE'):")
|
||||
emitln(" sys.stderr.write(f'{header}={value!r}\\n')")
|
||||
emitln("")
|
||||
emitln("__BACKSLASH = chr(0x5C)")
|
||||
emitln("__EOF = chr(0xFF)")
|
||||
emitln("__EOL = chr(10)")
|
||||
emitln("__QUOTE = chr(34)")
|
||||
@ -475,6 +476,12 @@ def emitheader():
|
||||
emitln(" sys.stderr.flush()")
|
||||
emitln(" exit(1)")
|
||||
emitln("")
|
||||
emitln("def __strlen(a: str) -> str:")
|
||||
emitln(" return str(len(a))")
|
||||
emitln("")
|
||||
emitln("def __intinc(a: str) -> str:")
|
||||
emitln(" return str(int(a) + 1)")
|
||||
emitln("")
|
||||
emitln("# ### END OF RUNTIME ### #")
|
||||
emitln("")
|
||||
|
||||
@ -489,6 +496,7 @@ def main():
|
||||
emitheader()
|
||||
|
||||
# Standard library constants
|
||||
mapsetkey("REGISTERID", "backslash", "__BACKSLASH")
|
||||
mapsetkey("REGISTERID", "eof", "__EOF")
|
||||
mapsetkey("REGISTERID", "eol", "__EOL")
|
||||
mapsetkey("REGISTERID", "quote", "__QUOTE")
|
||||
@ -500,6 +508,8 @@ def main():
|
||||
mapsetkey("REGISTERID", "emit", "__emit")
|
||||
mapsetkey("FUNCREG", "eq", "1")
|
||||
mapsetkey("REGISTERID", "eq", "__eq")
|
||||
mapsetkey("FUNCREG", "intinc", "1")
|
||||
mapsetkey("REGISTERID", "intinc", "__intinc")
|
||||
mapsetkey("FUNCREG", "lt", "1")
|
||||
mapsetkey("REGISTERID", "lt", "__lt")
|
||||
mapsetkey("FUNCREG", "not", "1")
|
||||
@ -518,6 +528,8 @@ def main():
|
||||
mapsetkey("REGISTERID", "stdincolno", "__stdincolno")
|
||||
mapsetkey("FUNCREG", "stdinlineno", "1")
|
||||
mapsetkey("REGISTERID", "stdinlineno", "__stdinlineno")
|
||||
mapsetkey("FUNCREG", "strlen", "1")
|
||||
mapsetkey("REGISTERID", "strlen", "__strlen")
|
||||
|
||||
while True:
|
||||
if eof == peek():
|
||||
|
||||
@ -472,6 +472,7 @@ emitheader:
|
||||
emitln " if os.environ.get('TRACE'):"
|
||||
emitln " sys.stderr.write(f'{header}={value!r}\\n')"
|
||||
emitln ""
|
||||
emitln "__BACKSLASH = chr(0x5C)"
|
||||
emitln "__EOF = chr(0xFF)"
|
||||
emitln "__EOL = chr(10)"
|
||||
emitln "__QUOTE = chr(34)"
|
||||
@ -534,6 +535,12 @@ emitheader:
|
||||
emitln " sys.stderr.flush()"
|
||||
emitln " exit(1)"
|
||||
emitln ""
|
||||
emitln "def __strlen(a: str) -> str:"
|
||||
emitln " return str(len(a))"
|
||||
emitln ""
|
||||
emitln "def __intinc(a: str) -> str:"
|
||||
emitln " return str(int(a) + 1)"
|
||||
emitln ""
|
||||
emitln "# ### END OF RUNTIME ### #"
|
||||
emitln ""
|
||||
/
|
||||
@ -551,6 +558,7 @@ emitfooter:
|
||||
main:
|
||||
emitheader
|
||||
|
||||
mapsetkey "REGISTERID" "backslash" "__BACKSLASH"
|
||||
mapsetkey "REGISTERID" "eof" "__EOF"
|
||||
mapsetkey "REGISTERID" "eol" "__EOL"
|
||||
mapsetkey "REGISTERID" "quote" "__QUOTE"
|
||||
@ -561,6 +569,8 @@ main:
|
||||
mapsetkey "REGISTERID" "emit" "__emit"
|
||||
mapsetkey "FUNCREG" "eq" "1"
|
||||
mapsetkey "REGISTERID" "eq" "__eq"
|
||||
mapsetkey "FUNCREG" "intinc" "1"
|
||||
mapsetkey "REGISTERID" "intinc" "__intinc"
|
||||
mapsetkey "FUNCREG" "lt" "1"
|
||||
mapsetkey "REGISTERID" "lt" "__lt"
|
||||
mapsetkey "FUNCREG" "not" "1"
|
||||
@ -579,6 +589,8 @@ main:
|
||||
mapsetkey "REGISTERID" "stdincolno" "__stdincolno"
|
||||
mapsetkey "FUNCREG" "stdinlineno" "1"
|
||||
mapsetkey "REGISTERID" "stdinlineno" "__stdinlineno"
|
||||
mapsetkey "FUNCREG" "strlen" "1"
|
||||
mapsetkey "REGISTERID" "strlen" "__strlen"
|
||||
|
||||
|
||||
forever
|
||||
|
||||
@ -574,6 +574,7 @@ emitheader:
|
||||
emitln "#include <string.h>"
|
||||
emitln ""
|
||||
emitln ""
|
||||
emitln "char __BACKSLASH[2] = {0x5C, 0};"
|
||||
emitln "char __EOF[2] = {0xFF, 0};"
|
||||
emitln "char __EOL[2] = {10, 0};"
|
||||
emitln "char __QUOTE[2] = {34, 0};"
|
||||
@ -798,6 +799,31 @@ emitheader:
|
||||
emitln ";"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * __strlen(char * inp)"
|
||||
emitln "{"
|
||||
emitln " char * buffer = malloc(20);"
|
||||
emitln " size_t len = strlen(inp);"
|
||||
emit " snprintf(buffer, 20, "
|
||||
emit quote
|
||||
emit "%zu"
|
||||
emit quote
|
||||
emitln ", len);"
|
||||
emitln " return buffer;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * __intinc(char * inp)"
|
||||
emitln "{"
|
||||
emitln " char * buffer = malloc(20);"
|
||||
emitln " char * endptr;"
|
||||
emitln " unsigned long long number = strtoull(inp, &endptr, 10);"
|
||||
emit " snprintf(buffer, 20, "
|
||||
emit quote
|
||||
emit "%llu"
|
||||
emit quote
|
||||
emitln ", number + 1);"
|
||||
emitln " return buffer;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "// ### END OF RUNTIME ### //"
|
||||
emitln ""
|
||||
return
|
||||
@ -824,6 +850,7 @@ main:
|
||||
|
||||
emitheader
|
||||
|
||||
mapsetkey "REGISTERID" "backslash" "__BACKSLASH"
|
||||
mapsetkey "REGISTERID" "eof" "__EOF"
|
||||
mapsetkey "REGISTERID" "eol" "__EOL"
|
||||
mapsetkey "REGISTERID" "quote" "__QUOTE"
|
||||
@ -834,6 +861,8 @@ main:
|
||||
mapsetkey "REGISTERID" "emit" "__emit"
|
||||
mapsetkey "FUNCREG" "eq" "1"
|
||||
mapsetkey "REGISTERID" "eq" "__eq"
|
||||
mapsetkey "FUNCREG" "intinc" "1"
|
||||
mapsetkey "REGISTERID" "intinc" "__intinc"
|
||||
mapsetkey "FUNCREG" "lt" "1"
|
||||
mapsetkey "REGISTERID" "lt" "__lt"
|
||||
mapsetkey "FUNCREG" "not" "1"
|
||||
@ -852,6 +881,8 @@ main:
|
||||
mapsetkey "REGISTERID" "stdincolno" "__stdincolno"
|
||||
mapsetkey "FUNCREG" "stdinlineno" "1"
|
||||
mapsetkey "REGISTERID" "stdinlineno" "__stdinlineno"
|
||||
mapsetkey "FUNCREG" "strlen" "1"
|
||||
mapsetkey "REGISTERID" "strlen" "__strlen"
|
||||
|
||||
forever
|
||||
calc char peek
|
||||
|
||||
12
3-lang0ll/.gitignore
vendored
Normal file
12
3-lang0ll/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/lang0ll*.bc
|
||||
/lang0ll*.c
|
||||
/lang0ll*.exe
|
||||
/lang0ll*.ll
|
||||
/lang0ll*.o
|
||||
/lang0ll*.s
|
||||
/runtimetest.bc
|
||||
/runtimetest.c
|
||||
/runtimetest.exe
|
||||
/runtimetest.ll
|
||||
/runtimetest.o
|
||||
/runtimetest.s
|
||||
BIN
3-lang0ll/A Gentle Introduction to LLVM IR · mcyoung.pdf
Normal file
BIN
3-lang0ll/A Gentle Introduction to LLVM IR · mcyoung.pdf
Normal file
Binary file not shown.
48
3-lang0ll/Makefile
Normal file
48
3-lang0ll/Makefile
Normal file
@ -0,0 +1,48 @@
|
||||
.SUFFIXES:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
LANG0C=$(CURDIR)/../2-lang0c/lang0c.exe
|
||||
|
||||
all: lang0ll.exe
|
||||
|
||||
%.exe: %.s
|
||||
clang -g $^ -o $@
|
||||
|
||||
%.s: %.bc
|
||||
llc --relocation-model=pic $^ -o $@
|
||||
|
||||
%.bc: %.ll
|
||||
llvm-as $^ -o $@
|
||||
|
||||
lang0ll0.c: lang0ll.lang0 $(LANG0C)
|
||||
cat $< | $(LANG0C) > $@
|
||||
|
||||
lang0ll0.o: lang0ll0.c
|
||||
gcc -g -c $<
|
||||
|
||||
lang0ll0.exe: lang0ll0.o
|
||||
gcc -g -o $@ $<
|
||||
|
||||
lang0ll1.ll: lang0ll.lang0 lang0ll0.exe
|
||||
cat $< | ./lang0ll0.exe > $@
|
||||
sed -i '/^.*; pre-declaration$$/d' $@
|
||||
# Cannot diff on the first iteration - platform change
|
||||
|
||||
lang0ll2.ll: lang0ll.lang0 lang0ll1.exe
|
||||
cat $< | ./lang0ll1.exe > $@
|
||||
sed -i '/^.*; pre-declaration$$/d' $@
|
||||
-diff lang0ll1.ll lang0ll2.ll
|
||||
|
||||
lang0ll.ll: lang0ll.lang0 lang0ll2.exe
|
||||
cat $< | ./lang0ll2.exe > $@
|
||||
sed -i '/^.*; pre-declaration$$/d' $@
|
||||
-diff lang0ll2.ll lang0ll.ll
|
||||
|
||||
foo.ll: foo.c
|
||||
clang -S -emit-llvm $^
|
||||
|
||||
clean:
|
||||
rm -f lang0ll*.c lang0ll*.ll lang0ll*.o lang0ll*.exe foo.ll foo.o foo.exe
|
||||
71
3-lang0ll/backup.ll
Normal file
71
3-lang0ll/backup.ll
Normal file
@ -0,0 +1,71 @@
|
||||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-linux-gnu"
|
||||
|
||||
declare noalias i8* @malloc(i64)
|
||||
|
||||
define i8* @__add(i8* %lft, i8* %rgt)
|
||||
{
|
||||
%lft_len = call i64 @__strlen(i8* %lft)
|
||||
%rgt_len = call i64 @__strlen(i8* %rgt)
|
||||
%new_len = add i64 %lft_len, %rgt_len
|
||||
|
||||
%res = call i8* @malloc(i64 %new_len)
|
||||
; todo: copy lft
|
||||
; todo: copy rgt
|
||||
; todo: set 0 byte
|
||||
ret i8* %res
|
||||
}
|
||||
|
||||
define i64 @__strlen(i8* %str)
|
||||
{
|
||||
start:
|
||||
br label %loop_start
|
||||
|
||||
loop_start:
|
||||
%i.0 = phi i64 [0, %start], [%i.new, %loop]
|
||||
%c_adr = getelementptr i8, i8* %str, i64 %i.0
|
||||
%c = load i8, i8* %c_adr
|
||||
%done = icmp eq i8 %c, 0
|
||||
br i1 %done, label %exit, label %loop
|
||||
|
||||
loop:
|
||||
%i.new = add i64 %i.0, 1
|
||||
br label %loop_start
|
||||
|
||||
exit:
|
||||
ret i64 %i.0
|
||||
}
|
||||
|
||||
define i8* @__mapgetkey(i8* %mapname, i8* %key, i8* %def)
|
||||
{
|
||||
; todo
|
||||
ret i8* %def
|
||||
}
|
||||
|
||||
define i8* @addstringchar(i8* %0, i8* %1)
|
||||
{
|
||||
; todo
|
||||
ret i8* %0
|
||||
}
|
||||
|
||||
define i8* @registerid(i8* %id_id)
|
||||
{
|
||||
%id_idname = call i8* @__mapgetkey(i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @str.01, i64 0, i64 0), i8* %id_id, i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @str.011, i64 0, i64 0))
|
||||
%1 = call i64 @__strlen(i8* %id_idname)
|
||||
%11 = icmp ne i64 %1, 0
|
||||
br i1 %11, label %lbl1, label %lbl11
|
||||
lbl1:
|
||||
ret i8* %id_idname
|
||||
lbl11:
|
||||
%id_idnamea = call i8* @__add(i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @str.0111, i64 0, i64 0), i8* %id_id)
|
||||
ret i8* %id_idnamea
|
||||
}
|
||||
|
||||
define i64 @main() {
|
||||
%res = call i64 @__strlen(i8* @str.01)
|
||||
ret i64 %res
|
||||
}
|
||||
|
||||
@str.01 = internal constant [11 x i8] c"REGISTERID\00"
|
||||
@str.011 = internal constant [0 x i8] c""
|
||||
@str.0111 = internal constant [3 x i8] c"id_"
|
||||
1027
3-lang0ll/lang0ll.lang0
Normal file
1027
3-lang0ll/lang0ll.lang0
Normal file
File diff suppressed because it is too large
Load Diff
19
3-lang0ll/notes.ll
Normal file
19
3-lang0ll/notes.ll
Normal file
@ -0,0 +1,19 @@
|
||||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-linux-gnu"
|
||||
|
||||
define i8* @addstringchar(i8* %0, i8* %1)
|
||||
{
|
||||
; todo
|
||||
ret i8* %0;
|
||||
}
|
||||
|
||||
define i8* @increaseindent(i8* %indent)
|
||||
{
|
||||
%indent.1 = call i8* @addstringchar(i8* %indent, i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i64 0, i64 0));
|
||||
%indent.2 = call i8* @addstringchar(i8* %indent.1, i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i64 0, i64 0));
|
||||
%indent.3 = call i8* @addstringchar(i8* %indent.2, i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i64 0, i64 0));
|
||||
%indent.4 = call i8* @addstringchar(i8* %indent.3, i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i64 0, i64 0));
|
||||
ret i8* %indent.4;
|
||||
}
|
||||
|
||||
@.str = private unnamed_addr constant [14 x i8] c"Hello, world!\00", align 1
|
||||
400
3-lang0ll/runtimetest.ll
Normal file
400
3-lang0ll/runtimetest.ll
Normal file
@ -0,0 +1,400 @@
|
||||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-linux-gnu"
|
||||
|
||||
%FILE = type opaque
|
||||
@stdout = global %FILE* null
|
||||
|
||||
declare void @exit(i32)
|
||||
declare i32 @fputs(i8*, %FILE*)
|
||||
declare i8* @malloc(i32)
|
||||
declare %FILE* @fdopen(i32, i8*)
|
||||
declare void @fclose(%FILE*)
|
||||
|
||||
@__BACKSLASH = internal constant [2 x i8] c"\\\00"
|
||||
@__EOF = internal constant [2 x i8] c"\\\FF"
|
||||
@__EOL = internal constant [2 x i8] c"\0A\00"
|
||||
@__QUOTE = internal constant [2 x i8] c"\22\00"
|
||||
@__FALSE = internal constant [1 x i8] c"\00"
|
||||
@__TRUE = internal constant [2 x i8] c"1\00"
|
||||
|
||||
define i8* @__drop_i8_type(i8* %0) alwaysinline readnone
|
||||
{
|
||||
ret i8* %0
|
||||
}
|
||||
define i8* @__eq(i8* %0, i8* %1)
|
||||
{
|
||||
%i = alloca i64, align 8
|
||||
|
||||
store i64 0, i64* %i
|
||||
br label %loop
|
||||
loop:
|
||||
%index = load i64, i64* %i
|
||||
%char0_adr = getelementptr i8, i8* %0, i64 %index
|
||||
%char1_adr = getelementptr i8, i8* %1, i64 %index
|
||||
|
||||
%char0 = load i8, i8* %char0_adr
|
||||
%char1 = load i8, i8* %char1_adr
|
||||
|
||||
%chars_differ = icmp ne i8 %char0, %char1
|
||||
br i1 %chars_differ, label %lbl_not_equal, label %lbl_equal
|
||||
lbl_equal:
|
||||
%string_end = icmp eq i8 %char0, 0
|
||||
br i1 %string_end, label %string_equal, label %next_char
|
||||
string_equal:
|
||||
ret i8* @__TRUE
|
||||
next_char:
|
||||
%next_index = add i64 %index, 1
|
||||
store i64 %next_index, i64* %i
|
||||
br label %loop
|
||||
|
||||
lbl_not_equal:
|
||||
ret i8* @__FALSE
|
||||
}
|
||||
define i8* @__lt(i8* %0, i8* %1)
|
||||
{
|
||||
%i = alloca i64, align 8
|
||||
|
||||
store i64 0, i64* %i
|
||||
br label %loop
|
||||
loop:
|
||||
%index = load i64, i64* %i
|
||||
%char0_adr = getelementptr i8, i8* %0, i64 %index
|
||||
%char1_adr = getelementptr i8, i8* %1, i64 %index
|
||||
|
||||
%char0 = load i8, i8* %char0_adr
|
||||
%char1 = load i8, i8* %char1_adr
|
||||
|
||||
%char0_eol = icmp eq i8 %char0, 0
|
||||
%char1_eol = icmp eq i8 %char1, 0
|
||||
|
||||
; if char0 == 0
|
||||
; if char1 == 0
|
||||
; return FALSE ; "" < "" === False
|
||||
; else
|
||||
; return TRUE ; "" < "." === True
|
||||
; endif
|
||||
; else
|
||||
; if char1 == 0
|
||||
; return FALSE ; "." < "" === False
|
||||
; else
|
||||
; if char0 < char1
|
||||
; return TRUE ; "a" < "b" === True
|
||||
; else
|
||||
; if char0 > char1
|
||||
; return FALSE ; "b" < "a" === False
|
||||
; else
|
||||
; jump next_char
|
||||
; endif
|
||||
; endif
|
||||
; endif
|
||||
; endif
|
||||
br i1 %char0_eol, label %lbl_char0_eol, label %lbl_char0_not_eol
|
||||
lbl_char0_eol:
|
||||
br i1 %char1_eol, label %lbl_not_smaller, label %lbl_smaller
|
||||
lbl_char0_not_eol:
|
||||
br i1 %char1_eol, label %lbl_not_smaller, label %lbl_char0_not_eol_char1_not_eol
|
||||
lbl_char0_not_eol_char1_not_eol:
|
||||
%char0_lt_char1 = icmp ult i8 %char0, %char1
|
||||
br i1 %char0_lt_char1, label %lbl_smaller, label %lbl_char0_ge_char1
|
||||
lbl_char0_ge_char1:
|
||||
%char0_gt_char1 = icmp ugt i8 %char0, %char1
|
||||
br i1 %char0_gt_char1, label %lbl_not_smaller, label %next_char
|
||||
next_char:
|
||||
%next_index = add i64 %index, 1
|
||||
store i64 %next_index, i64* %i
|
||||
br label %loop
|
||||
|
||||
lbl_smaller:
|
||||
ret i8* @__TRUE
|
||||
lbl_not_smaller:
|
||||
ret i8* @__FALSE
|
||||
}
|
||||
define i8* @__not(i8* %0)
|
||||
{
|
||||
%char0_adr = getelementptr i8, i8* %0, i64 0
|
||||
%char0 = load i8, i8* %char0_adr
|
||||
%char0_eol = icmp eq i8 %char0, 0
|
||||
br i1 %char0_eol, label %lbl_empty, label %lbl_not_empty
|
||||
lbl_empty:
|
||||
ret i8* @__TRUE;
|
||||
lbl_not_empty:
|
||||
ret i8* @__FALSE;
|
||||
}
|
||||
define i8* @__add(i8* %0, i8* %1)
|
||||
{
|
||||
ret i8* %0 ; STUB
|
||||
}
|
||||
define i8* @__emit(i8* %0)
|
||||
{
|
||||
%stdout_ptr = load %FILE*, %FILE** @stdout
|
||||
call i32 @fputs(i8* %0, %FILE* %stdout_ptr)
|
||||
ret i8* @__FALSE
|
||||
}
|
||||
define i8* @__trace(i8* %0, i8* %1)
|
||||
{
|
||||
ret i8* %0 ; STUB
|
||||
}
|
||||
define i8* @__peek()
|
||||
{
|
||||
ret i8* @__EOL ; STUB
|
||||
}
|
||||
define i8* @__skip()
|
||||
{
|
||||
ret i8* @__EOL ; STUB
|
||||
}
|
||||
define i8* @__stdinlineno()
|
||||
{
|
||||
ret i8* @__EOL ; STUB
|
||||
}
|
||||
define i8* @__stdincolno()
|
||||
{
|
||||
ret i8* @__EOL ; STUB
|
||||
}
|
||||
define i8* @__mapgetkey(i8* %0, i8* %1, i8* %2)
|
||||
{
|
||||
ret i8* %0 ; STUB
|
||||
}
|
||||
define i8* @__mapsetkey(i8* %0, i8* %1, i8* %2)
|
||||
{
|
||||
ret i8* %0 ; STUB
|
||||
}
|
||||
define i8* @__str_reverse(i8* %0, i64 %1)
|
||||
{
|
||||
%input_empty = icmp ule i64 %1, 1
|
||||
br i1 %input_empty, label %lbl_done, label %lbl_work_to_do
|
||||
lbl_work_to_do:
|
||||
|
||||
%arg1_sub1 = sub i64 %1, 1
|
||||
%rgidx_reg = alloca i64, align 8
|
||||
store i64 %arg1_sub1, i64* %rgidx_reg
|
||||
|
||||
%lfidx_reg = alloca i64, align 8
|
||||
store i64 0, i64* %lfidx_reg
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%rgidx = load i64, i64* %rgidx_reg
|
||||
%lfidx = load i64, i64* %lfidx_reg
|
||||
|
||||
%rgidx_le_lfidx = icmp ule i64 %rgidx, %lfidx
|
||||
br i1 %rgidx_le_lfidx, label %lbl_done, label %lbl_flip_one
|
||||
lbl_flip_one:
|
||||
%rgadr = getelementptr i8, i8* %0, i64 %rgidx
|
||||
%rgchr = load i8, i8* %rgadr
|
||||
%lfadr = getelementptr i8, i8* %0, i64 %lfidx
|
||||
%lfchr = load i8, i8* %lfadr
|
||||
|
||||
store i8 %lfchr, i8* %rgadr
|
||||
store i8 %rgchr, i8* %lfadr
|
||||
|
||||
%new_rgidx = sub i64 %rgidx, 1
|
||||
%new_lfidx = add i64 %lfidx, 1
|
||||
|
||||
store i64 %new_rgidx, i64* %rgidx_reg
|
||||
store i64 %new_lfidx, i64* %lfidx_reg
|
||||
|
||||
br label %loop
|
||||
|
||||
lbl_done:
|
||||
ret i8* %0;
|
||||
}
|
||||
define i8* @__i64_to_str(i64 %i)
|
||||
{
|
||||
%res = call i8* @malloc(i64 32)
|
||||
store i8 48, i8* %res ; Base case
|
||||
|
||||
%idx_reg = alloca i64, align 8
|
||||
store i64 0, i64* %idx_reg
|
||||
|
||||
%rem_idx = alloca i64, align 8
|
||||
store i64 %i, i64* %rem_idx
|
||||
|
||||
br label %loop
|
||||
loop:
|
||||
%rem = load i64, i64* %rem_idx
|
||||
%rem.eq0 = icmp eq i64 %rem, 0
|
||||
br i1 %rem.eq0, label %lbl_done, label %lbl_addchar
|
||||
lbl_addchar:
|
||||
%digit = urem i64 %rem, 10
|
||||
%char.0 = trunc i64 %digit to i8
|
||||
%char.1 = add i8 48, %char.0
|
||||
|
||||
%idx = load i64, i64* %idx_reg
|
||||
%char.adr = getelementptr i8, i8* %res, i64 %idx
|
||||
store i8 %char.1, i8* %char.adr
|
||||
|
||||
%newrem.0 = sub i64 %rem, %digit
|
||||
%newrem.1 = udiv i64 %newrem.0, 10
|
||||
store i64 %newrem.1, i64* %rem_idx
|
||||
%newidx = add i64 %idx, 1
|
||||
store i64 %newidx, i64* %idx_reg
|
||||
|
||||
br label %loop
|
||||
|
||||
lbl_done:
|
||||
; null terminator
|
||||
%nt_idx = load i64, i64* %idx_reg
|
||||
%nt_adr = getelementptr i8, i8* %res, i64 %nt_idx
|
||||
store i8 0, i8* %nt_adr
|
||||
|
||||
; By not increasing the index, the index is the length
|
||||
|
||||
%len = load i64, i64* %idx_reg
|
||||
%rev = call i8* @__str_reverse(i8* %res, i64 %len)
|
||||
ret i8 *%rev
|
||||
}
|
||||
define i8* @__strlen(i8* %0)
|
||||
{
|
||||
%i = alloca i64, align 8
|
||||
|
||||
store i64 0, i64* %i
|
||||
br label %loop
|
||||
loop:
|
||||
%index = load i64, i64* %i
|
||||
%char0_adr = getelementptr i8, i8* %0, i64 %index
|
||||
%char0 = load i8, i8* %char0_adr
|
||||
%char0_eol = icmp eq i8 %char0, 0
|
||||
br i1 %char0_eol, label %lbl_char0_eol, label %lbl_char0_not_eol
|
||||
lbl_char0_not_eol:
|
||||
%next_index = add i64 %index, 1
|
||||
store i64 %next_index, i64* %i
|
||||
br label %loop
|
||||
lbl_char0_eol:
|
||||
%len = load i64, i64* %i
|
||||
%res = call i8* @__i64_to_str(i64 %len)
|
||||
ret i8* %res;
|
||||
}
|
||||
define i8* @__intinc(i8* %0)
|
||||
{
|
||||
ret i8* %0 ; STUB
|
||||
}
|
||||
|
||||
|
||||
define void @test_result_1(i8* %func, i8* %arg0, i8* %result)
|
||||
{
|
||||
call i32 @__emit(i8* %func)
|
||||
call i32 @__emit(i8* @str.bracket)
|
||||
call i32 @__emit(i8* %arg0)
|
||||
call i32 @__emit(i8* @str.bracket_colon_space)
|
||||
call i32 @__emit(i8* %result)
|
||||
call i32 @__emit(i8* @__EOL)
|
||||
ret void
|
||||
}
|
||||
define void @test_result_2(i8* %func, i8* %arg0, i8* %arg1, i8* %result)
|
||||
{
|
||||
call i32 @__emit(i8* %func)
|
||||
call i32 @__emit(i8* @str.bracket)
|
||||
call i32 @__emit(i8* %arg0)
|
||||
call i32 @__emit(i8* @str.comma_space)
|
||||
call i32 @__emit(i8* %arg1)
|
||||
call i32 @__emit(i8* @str.bracket_colon_space)
|
||||
call i32 @__emit(i8* %result)
|
||||
call i32 @__emit(i8* @__EOL)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test_eq(i8* %0, i8* %1)
|
||||
{
|
||||
%result = call i8* @__eq(i8* %0, i8* %1)
|
||||
call void @test_result_2(i8* @str.eq, i8* %0, i8* %1, i8* %result)
|
||||
ret void
|
||||
}
|
||||
define void @test_lt(i8* %0, i8* %1)
|
||||
{
|
||||
%result = call i8* @__lt(i8* %0, i8* %1)
|
||||
call void @test_result_2(i8* @str.lt, i8* %0, i8* %1, i8* %result)
|
||||
ret void
|
||||
}
|
||||
define void @test_not(i8* %0)
|
||||
{
|
||||
%result = call i8* @__not(i8* %0)
|
||||
call void @test_result_1(i8* @str.not, i8* %0, i8* %result)
|
||||
ret void
|
||||
}
|
||||
define void @test_strlen(i8* %0)
|
||||
{
|
||||
%result = call i8* @__strlen(i8* %0)
|
||||
call void @test_result_1(i8* @str.strlen, i8* %0, i8* %result)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
define i64 @main()
|
||||
{
|
||||
%stdout_ptr = call %FILE* @fdopen(i32 1, i8* @str.w)
|
||||
store %FILE* %stdout_ptr, %FILE** @stdout
|
||||
|
||||
call void @test_eq(i8* @str., i8* @str.0)
|
||||
call void @test_eq(i8* @str.0, i8* @str.)
|
||||
call void @test_eq(i8* @str.0, i8* @str.0)
|
||||
call void @test_eq(i8* @str.a, i8* @str.a)
|
||||
call void @test_eq(i8* @str.a, i8* @str.b)
|
||||
call void @test_eq(i8* @str.a, i8* @str.c)
|
||||
call void @test_eq(i8* @str.b, i8* @str.a)
|
||||
call void @test_eq(i8* @str.b, i8* @str.b)
|
||||
call void @test_eq(i8* @str.b, i8* @str.c)
|
||||
call void @test_eq(i8* @str.c, i8* @str.a)
|
||||
call void @test_eq(i8* @str.c, i8* @str.b)
|
||||
call void @test_eq(i8* @str.c, i8* @str.c)
|
||||
call void @test_eq(i8* @str.left, i8* @str.right)
|
||||
call void @test_eq(i8* @str.left, i8* @str.left)
|
||||
call void @test_eq(i8* @str.right, i8* @str.left)
|
||||
call void @test_eq(i8* @str.right, i8* @str.right)
|
||||
|
||||
call void @test_lt(i8* @str.0, i8* @str.0)
|
||||
call void @test_lt(i8* @str.a, i8* @str.a)
|
||||
call void @test_lt(i8* @str.a, i8* @str.b)
|
||||
call void @test_lt(i8* @str.a, i8* @str.c)
|
||||
call void @test_lt(i8* @str.b, i8* @str.a)
|
||||
call void @test_lt(i8* @str.b, i8* @str.b)
|
||||
call void @test_lt(i8* @str.b, i8* @str.c)
|
||||
call void @test_lt(i8* @str.c, i8* @str.a)
|
||||
call void @test_lt(i8* @str.c, i8* @str.b)
|
||||
call void @test_lt(i8* @str.c, i8* @str.c)
|
||||
; `a` and `b` are expected to have length 1.
|
||||
|
||||
call void @test_not(i8* @str.)
|
||||
call void @test_not(i8* @str.0)
|
||||
call void @test_not(i8* @str.1)
|
||||
|
||||
call void @test_strlen(i8* @str.)
|
||||
call void @test_strlen(i8* @str.a)
|
||||
call void @test_strlen(i8* @str.eq)
|
||||
call void @test_strlen(i8* @str.not)
|
||||
call void @test_strlen(i8* @str.left)
|
||||
call void @test_strlen(i8* @str.right)
|
||||
call void @test_strlen(i8* @str.strlen)
|
||||
call void @test_strlen(i8* @str.explanation)
|
||||
call void @test_strlen(i8* @str.cats_paragraph)
|
||||
|
||||
|
||||
|
||||
call i32 @fclose(%FILE* %stdout_ptr)
|
||||
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
@str. = internal constant [1 x i8] c"\00"
|
||||
@str.0 = internal constant [2 x i8] c"0\00"
|
||||
@str.1 = internal constant [2 x i8] c"1\00"
|
||||
@str.2 = internal constant [2 x i8] c"2\00"
|
||||
@str.3 = internal constant [2 x i8] c"3\00"
|
||||
@str.4 = internal constant [2 x i8] c"4\00"
|
||||
@str.5 = internal constant [2 x i8] c"5\00"
|
||||
@str.6 = internal constant [2 x i8] c"6\00"
|
||||
@str.a = internal constant [2 x i8] c"a\00"
|
||||
@str.b = internal constant [2 x i8] c"b\00"
|
||||
@str.c = internal constant [2 x i8] c"c\00"
|
||||
@str.bracket = internal constant [2 x i8] c"(\00"
|
||||
@str.bracket_colon_space = internal constant [4 x i8] c"): \00"
|
||||
@str.comma_space = internal constant [3 x i8] c", \00"
|
||||
@str.eq = internal constant [3 x i8] c"eq\00"
|
||||
@str.left = internal constant [5 x i8] c"left\00"
|
||||
@str.lt = internal constant [3 x i8] c"lt\00"
|
||||
@str.not = internal constant [4 x i8] c"not\00"
|
||||
@str.right = internal constant [6 x i8] c"right\00"
|
||||
@str.strlen = internal constant [7 x i8] c"strlen\00"
|
||||
@str.w = internal constant [2 x i8] c"w\00"
|
||||
|
||||
@str.explanation = internal constant [135 x i8] c"Bitwise AND Operation: The and instruction performs a bitwise AND between the input value and the mask to isolate the smallest 8 bits.\00"
|
||||
@str.cats_paragraph = internal constant [1193 x i8] c"Cats are fascinating creatures that have captivated humans for thousands of years. Belonging to the family Felidae, they are known for their agility, sharp senses, and playful behavior. Cats communicate through a variety of vocalizations, body language, and purring. One remarkable feature is their keen hunting skills; they possess sharp retractable claws and excellent night vision, enabling them to stalk and capture prey effectively. Domesticated cats, often kept as pets, bring joy to many households. They exhibit a range of personalities, from solitary and aloof to affectionate and social. Cats also enjoy playing, often engaging in activities that mimic hunting, such as chasing toys or pouncing on moving objects. Additionally, their grooming habits help keep their fur clean and contain calming pheromones that promote bonding with their human companions. Studies suggest that having a cat can reduce stress and anxiety levels. This unique relationship invites appreciation for their independence and charm, as they provide companionship while often maintaining a mysterious aura. Overall, cats are beloved pets that enrich our lives with their unique attributes and companionship.\00"
|
||||
2
Makefile
2
Makefile
@ -2,10 +2,12 @@ all:
|
||||
$(MAKE) -C 0-lang0py all
|
||||
$(MAKE) -C 1-lang0py all
|
||||
$(MAKE) -C 2-lang0c all
|
||||
$(MAKE) -C 3-lang0ll all
|
||||
$(MAKE) -C tests all
|
||||
|
||||
clean:
|
||||
$(MAKE) -C 0-lang0py clean
|
||||
$(MAKE) -C 1-lang0py clean
|
||||
$(MAKE) -C 2-lang0c clean
|
||||
$(MAKE) -C 3-lang0ll clean
|
||||
$(MAKE) -C tests clean
|
||||
|
||||
14
README.md
14
README.md
@ -123,6 +123,10 @@ Writes the name and value of the variable passed to stderr if the TRACE environm
|
||||
|
||||
### Standard library constants
|
||||
|
||||
#### backslash
|
||||
|
||||
Backslash character.
|
||||
|
||||
#### eof
|
||||
|
||||
End of file character, zero byte.
|
||||
@ -155,6 +159,12 @@ Return true if the given strings are the same.
|
||||
|
||||
Return true if a would sort before b.
|
||||
|
||||
#### intinc
|
||||
|
||||
Assumes `a` is a string containing solely a decimal integer.
|
||||
|
||||
Returns a increased by one.
|
||||
|
||||
#### mapclear mapname
|
||||
|
||||
Maps are global and can be used from any function.
|
||||
@ -194,6 +204,10 @@ Returns the column number for stdin (starting at 1)
|
||||
|
||||
Returns the line number for stdin (starting at 1)
|
||||
|
||||
#### strlen a
|
||||
|
||||
Returns a string with the length of a.
|
||||
|
||||
### Typing
|
||||
|
||||
Every variable is of type string. Every function gets a number of strings as output, and returns another string.
|
||||
|
||||
@ -11,7 +11,7 @@ CFLAGS=-ggdb
|
||||
all: verify-results
|
||||
|
||||
Makefile.mk: generate-recipes.py $(wildcard test_*/test_*)
|
||||
python3 generate-recipes.py Makefile.mk it0 it1 it2
|
||||
python3 generate-recipes.py Makefile.mk it0 it1 it2 it3
|
||||
|
||||
include Makefile.mk
|
||||
|
||||
@ -29,6 +29,10 @@ clean:
|
||||
find build -name '*.it2.result' -delete
|
||||
find build -name '*.it2.stderr' -delete
|
||||
find build -name '*.it2.stdout' -delete
|
||||
find build -name '*.it3' -delete
|
||||
find build -name '*.it3.result' -delete
|
||||
find build -name '*.it3.stderr' -delete
|
||||
find build -name '*.it3.stdout' -delete
|
||||
find build -name '*.py' -delete
|
||||
find build -name '*.tmp' -delete
|
||||
|
||||
@ -85,3 +89,19 @@ build/%.it2.o: build/%.it2.c
|
||||
|
||||
build/%.it2: build/%.it2.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION)
|
||||
|
||||
###
|
||||
# it3
|
||||
|
||||
../3-lang0ll/lang0ll.exe: ../0-lang0py/lang0py.exe ../1-lang0py/lang0py.exe ../2-lang0c/lang0c.exe ../3-lang0ll/lang0ll.lang0
|
||||
$(MAKE) -C ../3-lang0ll
|
||||
|
||||
build/%.it3.ll: %.lang0 ../3-lang0ll/lang0ll.exe
|
||||
-cat $< | ../3-lang0ll/lang0ll.exe > $@.tmp 2> build/$*.it3.cmperr
|
||||
mv $@.tmp $@
|
||||
|
||||
build/%.it3.s: build/%.it3.ll
|
||||
llc --relocation-model=pic $^
|
||||
|
||||
build/%.it3: build/%.it3.s
|
||||
clang $^ -o $@
|
||||
|
||||
8
tests/build/test_stdlib_functions/.gitignore
vendored
8
tests/build/test_stdlib_functions/.gitignore
vendored
@ -24,3 +24,11 @@
|
||||
/*.it2.result
|
||||
/*.it2.stderr
|
||||
/*.it2.stdout
|
||||
/*.it3
|
||||
/*.it3.ll
|
||||
/*.it3.cmperr
|
||||
/*.it3.ll.tmp
|
||||
/*.it3.o
|
||||
/*.it3.result
|
||||
/*.it3.stderr
|
||||
/*.it3.stdout
|
||||
|
||||
@ -6,6 +6,7 @@ STAGE0_MAP = {
|
||||
'it0': '.py',
|
||||
'it1': '.py',
|
||||
'it2': '.c',
|
||||
'it3': '.ll',
|
||||
}
|
||||
|
||||
class Rule:
|
||||
|
||||
1
tests/test_stdlib_constants/test_backslash.exp.stdout
Normal file
1
tests/test_stdlib_constants/test_backslash.exp.stdout
Normal file
@ -0,0 +1 @@
|
||||
\
|
||||
3
tests/test_stdlib_constants/test_backslash.lang0
Normal file
3
tests/test_stdlib_constants/test_backslash.lang0
Normal file
@ -0,0 +1,3 @@
|
||||
main:
|
||||
emit backslash
|
||||
/
|
||||
@ -1,14 +1,3 @@
|
||||
func tst a b:
|
||||
declare var
|
||||
calc var add a b
|
||||
emit a
|
||||
emit " + "
|
||||
emit b
|
||||
emit " = "
|
||||
emit var
|
||||
emit eol
|
||||
/
|
||||
|
||||
main:
|
||||
declare var
|
||||
|
||||
|
||||
5
tests/test_stdlib_functions/test_intinc.exp.stdout
Normal file
5
tests/test_stdlib_functions/test_intinc.exp.stdout
Normal file
@ -0,0 +1,5 @@
|
||||
0 + 1: 1
|
||||
5 + 1: 6
|
||||
9 + 1: 10
|
||||
15 + 1: 16
|
||||
99 + 1: 100
|
||||
28
tests/test_stdlib_functions/test_intinc.lang0
Normal file
28
tests/test_stdlib_functions/test_intinc.lang0
Normal file
@ -0,0 +1,28 @@
|
||||
main:
|
||||
declare result
|
||||
|
||||
emit "0 + 1: "
|
||||
calc result intinc "0"
|
||||
emit result
|
||||
emit eol
|
||||
|
||||
emit "5 + 1: "
|
||||
calc result intinc "5"
|
||||
emit result
|
||||
emit eol
|
||||
|
||||
emit "9 + 1: "
|
||||
calc result intinc "9"
|
||||
emit result
|
||||
emit eol
|
||||
|
||||
emit "15 + 1: "
|
||||
calc result intinc "15"
|
||||
emit result
|
||||
emit eol
|
||||
|
||||
emit "99 + 1: "
|
||||
calc result intinc "99"
|
||||
emit result
|
||||
emit eol
|
||||
/
|
||||
4
tests/test_stdlib_functions/test_strlen.exp.stdout
Normal file
4
tests/test_stdlib_functions/test_strlen.exp.stdout
Normal file
@ -0,0 +1,4 @@
|
||||
strlen()=0
|
||||
strlen()=1
|
||||
strlen()=1
|
||||
strlen()=8
|
||||
23
tests/test_stdlib_functions/test_strlen.lang0
Normal file
23
tests/test_stdlib_functions/test_strlen.lang0
Normal file
@ -0,0 +1,23 @@
|
||||
main:
|
||||
declare var
|
||||
|
||||
calc var strlen ""
|
||||
emit "strlen()="
|
||||
emit var
|
||||
emit eol
|
||||
|
||||
calc var strlen "0"
|
||||
emit "strlen()="
|
||||
emit var
|
||||
emit eol
|
||||
|
||||
calc var strlen "1"
|
||||
emit "strlen()="
|
||||
emit var
|
||||
emit eol
|
||||
|
||||
calc var strlen "abcdefgh"
|
||||
emit "strlen()="
|
||||
emit var
|
||||
emit eol
|
||||
/
|
||||
Loading…
x
Reference in New Issue
Block a user