@stack = global [1000 x i8*] undef ; stack containing pointers to i8 @sp = global i64 0 ; global stack pointer (or rather: current number of elements) @lookahead = global i32 -1 ; current lookahead for input from stdin. ; -1 means no lookahead done yet. ; Constants @to_str = private unnamed_addr constant [3 x i8] c"%i\00" @true = global [2 x i8] c"1\00" @false = global [2 x i8] c"0\00" @printf_str_fmt = private unnamed_addr constant [3 x i8] c"%s\00" @crash_cust_str_fmt = private unnamed_addr constant [24 x i8] c"Crash: Custom error: %s\00" @err_stack_underflow = private unnamed_addr constant [18 x i8] c"Stack underflow!\0A\00" @err_eof = private unnamed_addr constant [9 x i8] c"At EOF!\0A\00" @err_type = private unnamed_addr constant [14 x i8] c"Invalid type!\00" @err_zero = private unnamed_addr constant [18 x i8] c"Division by zero!\00" ; External declarations %FILE = type opaque @stderr = external global %FILE* declare signext i32 @atol(i8*) declare i64 @strtol(i8*, i8**, i32 ) declare signext i32 @snprintf(i8*, ...) declare signext i32 @printf(i8*, ...) declare signext i32 @fprintf(%FILE*, i8*, ...) declare float @strtof(i8*, i8**) declare signext i32 @getchar() declare i8* @malloc(i16 zeroext) ; void *malloc(size_t) and size_t is 16 bits long (SIZE_MAX) declare i8* @calloc(i16 zeroext, i16 zeroext) declare void @exit(i32 signext) ; Debugging stuff @pushing = private unnamed_addr constant [14 x i8] c"Pushing [%s]\0A\00" @popped = private unnamed_addr constant [13 x i8] c"Popped [%s]\0a\00" @msg = private unnamed_addr constant [5 x i8] c"msg\0a\00" @int_to_str = private unnamed_addr constant [3 x i8] c"%i\00" @float_to_str = private unnamed_addr constant [3 x i8] c"%f\00" ;typedef enum {INT = 1, FLOAT = 2, STRING = 3} elem_type; ;struct stack_elem { ; elem_type type; ; union { ; int ival; ; float fval; ; char *sval; ; }; ;}; %struct.stack_elem = type { i32, %union.anon } %union.anon = type { i8* } @.str = private unnamed_addr constant [33 x i8] c"call int add with a=%i and b=%i\0A\00", align 1 @.str1 = private unnamed_addr constant [35 x i8] c"call float add with a=%f and b=%f\0A\00", align 1 @.str2 = private unnamed_addr constant [15 x i8] c"failed to add\0A\00", align 1 ; Function definitions ; Get number of element on the stack define i64 @stack_get_size() { %sp = load i64* @sp ret i64 %sp } ; Push the stack size onto the stack define void @underflow_check() { %stack_size = call i64 @stack_get_size() call void @push_int(i64 %stack_size) ret void } ; Exit the program if stack is empty (prints error to stderr). define void @underflow_assert() { %stack_size = call i64 @stack_get_size() %stack_empty = icmp eq i64 %stack_size, 0 br i1 %stack_empty, label %uas_crash, label %uas_okay uas_crash: %err = getelementptr [18 x i8]* @err_stack_underflow, i8 0, i8 0 %stderr = load %FILE** @stderr call i32(%FILE*, i8*, ...)* @fprintf(%FILE* %stderr, i8* %err) call void @exit(i32 1) ret void uas_okay: ret void } ; Pop stack and print result string define void @print() { ; TODO: Check if the top stack element is a string and crash if it is not. call void @underflow_assert() %fmt = getelementptr [3 x i8]* @printf_str_fmt, i8 0, i8 0 %val = call i8* @pop() call i32(i8*, ...)* @printf(i8* %fmt, i8* %val) ret void } ; Pop stack, print result string to stderr and exit the program. define void @crash(i1 %is_custom_error) { ; TODO: Check if the top stack element is a string and crash if it is not. call void @underflow_assert() br i1 %is_custom_error, label %custom_error, label %raw_error custom_error: %cust_fmt = getelementptr [24 x i8]* @crash_cust_str_fmt, i8 0, i8 0 br label %end raw_error: %raw_fmt = getelementptr [3 x i8]* @printf_str_fmt, i8 0, i8 0 br label %end end: %fmt = phi i8* [%raw_fmt, %raw_error], [%cust_fmt, %custom_error] %val = call i8* @pop() %stderr = load %FILE** @stderr call i32(%FILE*, i8*, ...)* @fprintf(%FILE* %stderr, i8* %fmt, i8* %val) ; Now, crash! call void @exit(i32 1) ret void } ; Get a byte of input from stdin and push it. ; Crashes the program on errors. define void @input() { %read = call i32 @input_get() %err = icmp slt i32 %read, 0 br i1 %err, label %error, label %push error: %at_eof = getelementptr [9 x i8]* @err_eof, i64 0, i64 0 call void @push(i8* %at_eof) call void @crash(i1 0) ret void push: %byte = trunc i32 %read to i8 %buffer_addr = call i8* @calloc(i16 1, i16 2) store i8 %byte, i8* %buffer_addr call void @push(i8* %buffer_addr) ret void } ; Get a byte of input from stdin. Returns < 0 on error. ; This can be used together with input_peek(). define i32 @input_get() { %lookahead = load i32* @lookahead %need_read = icmp slt i32 %lookahead, 0 br i1 %need_read, label %ig_read, label %ig_lookahead ig_lookahead: store i32 -1, i32* @lookahead ret i32 %lookahead ig_read: %read = call i32 @getchar() ret i32 %read } ; Peek a byte of input from stdin. Returns < 0 on error. ; Successive calls to this function without interspersed calls ; to input_read() return the same value. define i32 @input_peek() { %read = call i32 @input_get() store i32 %read, i32* @lookahead ret i32 %read } ; If stdin is at EOF, push 1, else 0. define void @eof_check() { %peek = call i32 @input_peek() %is_eof = icmp slt i32 %peek, 0 br i1 %is_eof, label %at_eof, label %not_at_eof at_eof: %true = getelementptr [2 x i8]* @true, i8 0, i8 0 call void @push(i8* %true) ret void not_at_eof: %false = getelementptr [2 x i8]* @false, i8 0, i8 0 call void @push(i8* %false) ret void } define void @push(i8* %str_ptr) { ; dereferencing @sp by loading value into memory %sp = load i64* @sp ; get position on the stack, the stack pointer points to. this is the top of ; the stack. ; nice getelementptr FAQ: http://llvm.org/docs/GetElementPtr.html ; value of pointer type, index, field %top = getelementptr [1000 x i8*]* @stack, i8 0, i64 %sp ; the contents of memory are updated to contain %str_ptr at the location ; specified by the %addr operand store i8* %str_ptr, i8** %top ; increase stack pointer to point to new free, top of stack %newsp = add i64 %sp, 1 store i64 %newsp, i64* @sp ret void } ; pops element from stack and converts in integer ; returns the element, in case of error undefined define i64 @pop_int(){ ; pop %top = call i8* @pop() ; convert to int, check for error %top_int0 = call i32 @atol(i8* %top) %top_int1 = sext i32 %top_int0 to i64 ; return ret i64 %top_int1 } define void @push_float(double %top_float) { ; allocate memory to store string in ; TODO: Make sure this is free()'d at _some_ point during ; program execution. %buffer_addr = call i8* @malloc(i16 128) %to_str_ptr = getelementptr [3 x i8]* @float_to_str, i64 0, i64 0 ; convert to string call i32(i8*, ...)* @snprintf( i8* %buffer_addr, i16 128, i8* %to_str_ptr, double %top_float) ; push on stack call void(i8*)* @push(i8* %buffer_addr) ret void } define void @push_int(i64 %top_int) { ; allocate memory to store string in ; TODO: Make sure this is free()'d at _some_ point during ; program execution. %buffer_addr = call i8* @malloc(i16 128) %to_str_ptr = getelementptr [3 x i8]* @int_to_str, i64 0, i64 0 ; convert to string call i32(i8*, ...)* @snprintf( i8* %buffer_addr, i16 128, i8* %to_str_ptr, i64 %top_int) ; push on stack call void(i8*)* @push(i8* %buffer_addr) ret void } define i32 @mult() { ; return value of this function %func_result = alloca i32, align 4 ; allocate memory on stack to hold our structures that contains the type ; of stack element and its casted value %new_elem_a = alloca %struct.stack_elem, align 8 %new_elem_b = alloca %struct.stack_elem, align 8 ; get top of stack call void @underflow_assert() %number_a = call i8* @pop() ; get second top of stack call void @underflow_assert() %number_b = call i8* @pop() ; get type of number_a %ret_a = call i32 @get_stack_elem(i8* %number_a, %struct.stack_elem* %new_elem_a) %is_zero_a = icmp slt i32 %ret_a, 0 br i1 %is_zero_a, label %exit_with_failure, label %get_type_b ;############################################################################## ; integer multiplication ;############################################################################## get_type_b: ; get type of number_b %ret_b = call i32 @get_stack_elem(i8* %number_b, %struct.stack_elem* %new_elem_b) %is_zero_b = icmp slt i32 %ret_b, 0 br i1 %is_zero_b, label %exit_with_failure, label %type_check_a_int type_check_a_int: ; first, load the new_elem_a.type element. check whether it is 1 (aka INT). %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %is_int_a = icmp eq i32 %type_a, 1 br i1 %is_int_a, label %type_check_b_int, label %type_check_a_float type_check_b_int: ; first, load the new_elem_b.type element. check whether it is 1 (aka INT). %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %add_int, label %type_check_a_float add_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %ival_a_cast = bitcast %union.anon* %ival_a_ptr to i64* %ival_a = load i64* %ival_a_cast, align 4 ; get new_elem_b.ival that contains the casted integer value %ival_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %ival_b_cast = bitcast %union.anon* %ival_b_ptr to i64* %ival_b = load i64* %ival_b_cast, align 4 ; add the two integers and store result on the stack %ires = mul i64 %ival_a, %ival_b call void(i64)* @push_int(i64 %ires) br label %exit_with_success ;############################################################################## ; floating point multiplication ;############################################################################## type_check_a_float: %ftype_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %ftype_a = load i32* %ftype_a_ptr, align 4 %is_float_a = icmp eq i32 %ftype_a, 2 br i1 %is_float_a, label %type_check_b_float, label %exit_with_invalid_type type_check_b_float: %ftype_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %ftype_b = load i32* %ftype_b_ptr, align 4 %is_float_b = icmp eq i32 %ftype_b, 2 br i1 %is_float_b, label %mult_float, label %exit_with_invalid_type mult_float: ; get new_elem_a.fval that contains the float value %fval_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %fval_a_cast = bitcast %union.anon* %fval_a_ptr to float* %fval_a = load float* %fval_a_cast, align 4 %fval_a_d = fpext float %fval_a to double ; get new_elem_b.fval that contains the float value %fval_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %fval_b_cast = bitcast %union.anon* %fval_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 %fval_b_d = fpext float %fval_b to double ; sub the two floats and store result on the stack %fres= fmul double %fval_a_d, %fval_b_d call void(double)* @push_float(double %fres) br label %exit_with_success exit_with_success: store i32 0, i32* %func_result br label %exit exit_with_invalid_type: call void(i8*)* @push(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: store i32 -1, i32* %func_result br label %exit exit: %result = load i32* %func_result ret i32 %result } define i32 @rem() { ; return value of this function %func_result = alloca i32, align 4 ; allocate memory on stack to hold our structures that contains the type ; of stack element and its casted value %new_elem_a = alloca %struct.stack_elem, align 8 %new_elem_b = alloca %struct.stack_elem, align 8 ; get top of stack call void @underflow_assert() %number_a = call i8* @pop() ; get second top of stack call void @underflow_assert() %number_b = call i8* @pop() ; get type of number_a %ret_a = call i32 @get_stack_elem(i8* %number_a, %struct.stack_elem* %new_elem_a) %is_zero_a = icmp slt i32 %ret_a, 0 br i1 %is_zero_a, label %exit_with_failure, label %get_type_b ;############################################################################## ; integer remainder ;############################################################################## get_type_b: ; get type of number_b %ret_b = call i32 @get_stack_elem(i8* %number_b, %struct.stack_elem* %new_elem_b) %is_zero_b = icmp slt i32 %ret_b, 0 br i1 %is_zero_b, label %exit_with_failure, label %type_check_a_int type_check_a_int: ; first, load the new_elem_a.type element. check whether it is 1 (aka INT). %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %is_int_a = icmp eq i32 %type_a, 1 br i1 %is_int_a, label %type_check_b_int, label %type_check_a_float type_check_b_int: ; first, load the new_elem_b.type element. check whether it is 1 (aka INT). %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %rem_int, label %type_check_a_float rem_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %ival_a_cast = bitcast %union.anon* %ival_a_ptr to i32* %ival_a = load i32* %ival_a_cast, align 4 ; get new_elem_b.ival that contains the casted integer value %ival_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %ival_b_cast = bitcast %union.anon* %ival_b_ptr to i32* %ival_b = load i32* %ival_b_cast, align 4 ; add the two integers and store result on the stack %ires = srem i32 %ival_a, %ival_b %lres = sext i32 %ires to i64 call void(i64)* @push_int(i64 %lres) br label %exit_with_success ;############################################################################## ; floating point remainder ;############################################################################## type_check_a_float: %ftype_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %ftype_a = load i32* %ftype_a_ptr, align 4 %is_float_a = icmp eq i32 %ftype_a, 2 br i1 %is_float_a, label %type_check_b_float, label %exit_with_invalid_type type_check_b_float: %ftype_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %ftype_b = load i32* %ftype_b_ptr, align 4 %is_float_b = icmp eq i32 %ftype_b, 2 br i1 %is_float_b, label %rem_float, label %exit_with_invalid_type rem_float: ; get new_elem_a.fval that contains the float value %fval_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %fval_a_cast = bitcast %union.anon* %fval_a_ptr to float* %fval_a = load float* %fval_a_cast, align 4 %fval_a_d = fpext float %fval_a to double ; get new_elem_b.fval that contains the float value %fval_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %fval_b_cast = bitcast %union.anon* %fval_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 %fval_b_d = fpext float %fval_b to double ; sub the two floats and store result on the stack %fres= frem double %fval_a_d, %fval_b_d call void(double)* @push_float(double %fres) br label %exit_with_success exit_with_success: store i32 0, i32* %func_result br label %exit exit_with_invalid_type: call void(i8*)* @push(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: store i32 -1, i32* %func_result br label %exit exit: %result = load i32* %func_result ret i32 %result } define i32 @sub() { ; return value of this function %func_result = alloca i32, align 4 ; allocate memory on stack to hold our structures that contains the type ; of stack element and its casted value %new_elem_a = alloca %struct.stack_elem, align 8 %new_elem_b = alloca %struct.stack_elem, align 8 ; get top of stack call void @underflow_assert() %number_a = call i8* @pop() ; get second top of stack call void @underflow_assert() %number_b = call i8* @pop() ; get type of number_a %ret_a = call i32 @get_stack_elem(i8* %number_a, %struct.stack_elem* %new_elem_a) %is_zero_a = icmp slt i32 %ret_a, 0 br i1 %is_zero_a, label %exit_with_failure, label %get_type_b ;############################################################################## ; integer subtraction ;############################################################################## get_type_b: ; get type of number_b %ret_b = call i32 @get_stack_elem(i8* %number_b, %struct.stack_elem* %new_elem_b) %is_zero_b = icmp slt i32 %ret_b, 0 br i1 %is_zero_b, label %exit_with_failure, label %type_check_a_int type_check_a_int: ; first, load the new_elem_a.type element. check whether it is 1 (aka INT). %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %is_int_a = icmp eq i32 %type_a, 1 br i1 %is_int_a, label %type_check_b_int, label %type_check_a_float type_check_b_int: ; first, load the new_elem_b.type element. check whether it is 1 (aka INT). %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %sub_int, label %type_check_a_float sub_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %ival_a_cast = bitcast %union.anon* %ival_a_ptr to i64* %ival_a = load i64* %ival_a_cast, align 4 ; get new_elem_b.ival that contains the casted integer value %ival_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %ival_b_cast = bitcast %union.anon* %ival_b_ptr to i64* %ival_b = load i64* %ival_b_cast, align 4 ; add the two integers and store result on the stack %ires = sub i64 %ival_a, %ival_b call void(i64)* @push_int(i64 %ires) br label %exit_with_success ;############################################################################## ; floating point subtraction ;############################################################################## type_check_a_float: %ftype_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %ftype_a = load i32* %ftype_a_ptr, align 4 %is_float_a = icmp eq i32 %ftype_a, 2 br i1 %is_float_a, label %type_check_b_float, label %exit_with_invalid_type type_check_b_float: %ftype_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %ftype_b = load i32* %ftype_b_ptr, align 4 %is_float_b = icmp eq i32 %ftype_b, 2 br i1 %is_float_b, label %sub_float, label %exit_with_invalid_type sub_float: ; get new_elem_a.fval that contains the float value %fval_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %fval_a_cast = bitcast %union.anon* %fval_a_ptr to float* %fval_a = load float* %fval_a_cast, align 4 %fval_a_d = fpext float %fval_a to double ; get new_elem_b.fval that contains the float value %fval_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %fval_b_cast = bitcast %union.anon* %fval_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 %fval_b_d = fpext float %fval_b to double ; sub the two floats and store result on the stack %fres= fsub double %fval_a_d, %fval_b_d call void(double)* @push_float(double %fres) br label %exit_with_success exit_with_success: store i32 0, i32* %func_result br label %exit exit_with_invalid_type: call void(i8*)* @push(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: store i32 -1, i32* %func_result br label %exit exit: %result = load i32* %func_result ret i32 %result } define i32 @add() { ; return value of this function %func_result = alloca i32, align 4 ; allocate memory on stack to hold our structures that contains the type ; of stack element and its casted value %new_elem_a = alloca %struct.stack_elem, align 8 %new_elem_b = alloca %struct.stack_elem, align 8 ; get top of stack call void @underflow_assert() %number_a = call i8* @pop() ; get second top of stack call void @underflow_assert() %number_b = call i8* @pop() ; get type of number_a %ret_a = call i32 @get_stack_elem(i8* %number_a, %struct.stack_elem* %new_elem_a) %is_zero_a = icmp slt i32 %ret_a, 0 br i1 %is_zero_a, label %exit_with_failure, label %get_type_b ;############################################################################## ; integer addition ;############################################################################## get_type_b: ; get type of number_b %ret_b = call i32 @get_stack_elem(i8* %number_b, %struct.stack_elem* %new_elem_b) %is_zero_b = icmp slt i32 %ret_b, 0 br i1 %is_zero_b, label %exit_with_failure, label %type_check_a_int type_check_a_int: ; first, load the new_elem_a.type element. check whether it is 1 (aka INT). %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %is_int_a = icmp eq i32 %type_a, 1 br i1 %is_int_a, label %type_check_b_int, label %type_check_a_float type_check_b_int: ; first, load the new_elem_b.type element. check whether it is 1 (aka INT). %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %add_int, label %type_check_a_float add_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %ival_a_cast = bitcast %union.anon* %ival_a_ptr to i64* %ival_a = load i64* %ival_a_cast, align 4 ; get new_elem_b.ival that contains the casted integer value %ival_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %ival_b_cast = bitcast %union.anon* %ival_b_ptr to i64* %ival_b = load i64* %ival_b_cast, align 4 ; add the two integers and store result on the stack %ires = add i64 %ival_a, %ival_b call void(i64)* @push_int(i64 %ires) br label %exit_with_success ;############################################################################## ; floating point addition ;############################################################################## type_check_a_float: %ftype_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %ftype_a = load i32* %ftype_a_ptr, align 4 %is_float_a = icmp eq i32 %ftype_a, 2 br i1 %is_float_a, label %type_check_b_float, label %exit_with_invalid_type type_check_b_float: %ftype_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %ftype_b = load i32* %ftype_b_ptr, align 4 %is_float_b = icmp eq i32 %ftype_b, 2 br i1 %is_float_b, label %add_float, label %exit_with_invalid_type add_float: ; get new_elem_a.fval that contains the float value %fval_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %fval_a_cast = bitcast %union.anon* %fval_a_ptr to float* %fval_a = load float* %fval_a_cast, align 4 %fval_a_d = fpext float %fval_a to double ; get new_elem_b.fval that contains the float value %fval_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %fval_b_cast = bitcast %union.anon* %fval_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 %fval_b_d = fpext float %fval_b to double ; add the two floats and store result on the stack %fres= fadd double %fval_a_d, %fval_b_d call void(double)* @push_float(double %fres) br label %exit_with_success exit_with_success: store i32 0, i32* %func_result br label %exit exit_with_invalid_type: call void(i8*)* @push(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: store i32 -1, i32* %func_result br label %exit exit: %result = load i32* %func_result ret i32 %result } define void @sub_int() { ; get top of stack %top_1 = call i64()* @pop_int() ; get second top of stack %top_2 = call i64()* @pop_int() ; sub the two values %res = sub i64 %top_1, %top_2 ; store result on stack call void(i64)* @push_int(i64 %res) ret void } define i32 @div() { ; return value of this function %func_result = alloca i32, align 4 ; allocate memory on stack to hold our structures that contains the type ; of stack element and its casted value %new_elem_a = alloca %struct.stack_elem, align 8 %new_elem_b = alloca %struct.stack_elem, align 8 ; get top of stack call void @underflow_assert() %number_a = call i8* @pop() ; get second top of stack call void @underflow_assert() %number_b = call i8* @pop() ; get type of number_a %ret_a = call i32 @get_stack_elem(i8* %number_a, %struct.stack_elem* %new_elem_a) %is_zero_a = icmp slt i32 %ret_a, 0 br i1 %is_zero_a, label %exit_with_failure, label %get_type_b ;############################################################################## ; integer division ;############################################################################## get_type_b: ; get type of number_b %ret_b = call i32 @get_stack_elem(i8* %number_b, %struct.stack_elem* %new_elem_b) %is_zero_b = icmp slt i32 %ret_b, 0 br i1 %is_zero_b, label %exit_with_failure, label %type_check_a_int type_check_a_int: ; first, load the new_elem_a.type element. check whether it is 1 (aka INT). %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %is_int_a = icmp eq i32 %type_a, 1 br i1 %is_int_a, label %type_check_b_int, label %type_check_a_float type_check_b_int: ; first, load the new_elem_b.type element. check whether it is 1 (aka INT). %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %div_int, label %type_check_a_float div_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %ival_a_cast = bitcast %union.anon* %ival_a_ptr to i32* %ival_a = load i32* %ival_a_cast, align 4 ; get new_elem_b.ival that contains the casted integer value %ival_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %ival_b_cast = bitcast %union.anon* %ival_b_ptr to i32* %ival_b = load i32* %ival_b_cast, align 4 ; prevent division by zero %div_by_zero = icmp eq i32 %ival_b, 0 br i1 %div_by_zero, label %exit_with_zero, label %div_int_ok div_int_ok: ; divide the two integers and store result on the stack %ires = sdiv i32 %ival_a, %ival_b %lres = sext i32 %ires to i64 call void(i64)* @push_int(i64 %lres) br label %exit_with_success ;############################################################################## ; floating point division ;############################################################################## type_check_a_float: %ftype_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %ftype_a = load i32* %ftype_a_ptr, align 4 %is_float_a = icmp eq i32 %ftype_a, 2 br i1 %is_float_a, label %type_check_b_float, label %exit_with_invalid_type type_check_b_float: %ftype_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %ftype_b = load i32* %ftype_b_ptr, align 4 %is_float_b = icmp eq i32 %ftype_b, 2 br i1 %is_float_b, label %div_float, label %exit_with_invalid_type div_float: ; get new_elem_a.fval that contains the float value %fval_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %fval_a_cast = bitcast %union.anon* %fval_a_ptr to float* %fval_a = load float* %fval_a_cast, align 4 %fval_a_d = fpext float %fval_a to double ; get new_elem_b.fval that contains the float value %fval_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %fval_b_cast = bitcast %union.anon* %fval_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 ; prevent division by zero %div_by_zero_f = fcmp oeq float %fval_b, 0.0 br i1 %div_by_zero_f, label %exit_with_zero, label %div_float_ok div_float_ok: ; divide the two floats and store result on the stack %fval_b_d = fpext float %fval_b to double %fres= fdiv double %fval_a_d, %fval_b_d call void(double)* @push_float(double %fres) br label %exit_with_success exit_with_success: store i32 0, i32* %func_result br label %exit exit_with_zero: call void(i8*)* @push(i8* getelementptr inbounds( [18 x i8]* @err_zero, i64 0, i64 0)) br label %exit_with_failure exit_with_invalid_type: call void(i8*)* @push(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: store i32 -1, i32* %func_result br label %exit exit: %result = load i32* %func_result ret i32 %result } @main.number_a = private unnamed_addr constant [4 x i8] c"-57\00" @main.number_b = private unnamed_addr constant [4 x i8] c"-58\00" define i32 @main_div() { ; push two numbers on the stack %number0 = getelementptr [4 x i8]* @main.number_a, i64 0, i64 0 %number1 = getelementptr [4 x i8]* @main.number_b, i64 0, i64 0 call void(i8*)* @push(i8* %number0) call void(i8*)* @push(i8* %number1) call i32 @div() %result = call i8* @pop() call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([13 x i8]* @popped, i32 0, i32 0), i8* %result) ret i32 0 } define i32 @main_equal() { ; push two numbers on the stack %number0 = getelementptr [4 x i8]* @main.number_a, i64 0, i64 0 %number1 = getelementptr [4 x i8]* @main.number_b, i64 0, i64 0 call void(i8*)* @push(i8* %number0) call void(i8*)* @push(i8* %number1) call i32 @equal() %result = call i8* @pop() call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([13 x i8]* @popped, i32 0, i32 0), i8* %result) ret i32 0 } define i8* @peek() { %sp = load i64* @sp %top_of_stack = sub i64 %sp, 1 %addr = getelementptr [1000 x i8*]* @stack, i8 0, i64 %top_of_stack %val = load i8** %addr ret i8* %val } define i8* @pop() { %val = call i8*()* @peek() %sp = load i64* @sp %top_of_stack = sub i64 %sp, 1 store i64 %top_of_stack, i64* @sp ret i8* %val } ; TODO: free alloated space of input strings define void @strapp() { entry: %str2 = call i8*()* @pop() %str1 = call i8*()* @pop() ; compute length of input strings (TODO: maybe isolate strlen function for this purpose) call void(i8*)* @push(i8* %str1) call void()* @strlen() %len_str1 = call i64()* @pop_int() call void(i8*)* @push(i8* %str2) call void()* @strlen() %len_str2 = call i64()* @pop_int() ; allocate space for result string %len_result_1 = add i64 %len_str1, %len_str2 %len_result_2 = add i64 %len_result_1, 1 %len_result_3 = trunc i64 %len_result_2 to i16 %result = call i8* @malloc(i16 %len_result_3) ; copy first string br label %loop1 loop1: %i = phi i64 [0, %entry], [ %next_i, %loop1 ] %next_i = add i64 %i, 1 %addr = getelementptr i8* %str1, i64 %i %c = load i8* %addr %result_addr = getelementptr i8* %result, i64 %i store i8 %c, i8* %result_addr %cond = icmp eq i8 %c, 0 br i1 %cond, label %finished, label %loop1 finished: ; copy second string br label %loop2 loop2: %j = phi i64 [0, %finished], [ %next_j, %loop2 ] %next_j = add i64 %j, 1 %addr2 = getelementptr i8* %str2, i64 %j %c2 = load i8* %addr2 %k = add i64 %j, %len_str1 %result_addr2 = getelementptr i8* %result, i64 %k store i8 %c2, i8* %result_addr2 %cond2 = icmp eq i8 %c2, 0 br i1 %cond2, label %finished2, label %loop2 finished2: call void(i8*)* @push(i8* %result) ret void } define void @strlen() { entry: %str = call i8*()* @pop() br label %loop loop: %i = phi i64 [1, %entry ], [ %next_i, %loop ] %next_i = add i64 %i, 1 %addr = getelementptr i8* %str, i64 %i %c = load i8* %addr %cond = icmp eq i8 %c, 0 br i1 %cond, label %finished, label %loop finished: call void(i64)* @push_int(i64 %i) ret void } define void @streq() { entry: %str1 = call i8*()* @pop() %str2 = call i8*()* @pop() br label %loop loop: ; the phi instruction says that coming from the 'entry' label i is 1 ; otherwise (coming from 'cont') i will be 'next_i' %i = phi i64 [ 1, %entry ], [ %next_i, %cont ] ; the the actual character %addr1 = getelementptr i8* %str1, i64 %i %addr2 = getelementptr i8* %str2, i64 %i %c1 = load i8* %addr1 %c2 = load i8* %addr2 ; if equal, jump to next character otherwise jump to 'fail' %cond = icmp eq i8 %c1, %c2 br i1 %cond, label %cont, label %fail cont: %next_i = add i64 %i, 1 %cond2 = icmp eq i8 %c1, 0 br i1 %cond2, label %success, label %loop success: %t = getelementptr [2 x i8]* @true, i64 0, i64 0 call void(i8*)* @push(i8* %t) ret void fail: %f = getelementptr [2 x i8]* @false, i64 0, i64 0 call void(i8*)* @push(i8* %f) ret void } define i32 @finish(){ ret i32 0 } ;############################################################################## ; equal ;############################################################################## define i32 @equal(){ ; return value of this function %func_result = alloca i32, align 4 %new_elem_a = alloca %struct.stack_elem, align 8 %new_elem_b = alloca %struct.stack_elem, align 8 ; get top call void @underflow_assert() %number_a = call i8* @pop() ; get top-1 call void @underflow_assert() %number_b = call i8* @pop() ; get type of number_a %ret_a = call i32 @get_stack_elem(i8* %number_a, %struct.stack_elem* %new_elem_a) %is_zero_a = icmp slt i32 %ret_a, 0 br i1 %is_zero_a, label %exit_with_failure, label %get_type_b get_type_b: ; get type of number_b %ret_b = call i32 @get_stack_elem(i8* %number_b, %struct.stack_elem* %new_elem_b) %is_zero_b = icmp slt i32 %ret_b, 0 br i1 %is_zero_b, label %exit_with_failure, label %type_check_a_int type_check_a_int: ; first, load the new_elem_a.type element. check whether it is 1 (aka INT). %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %is_int_a = icmp eq i32 %type_a, 1 br i1 %is_int_a, label %type_check_b_int, label %type_check_a_float type_check_b_int: ; first, load the new_elem_b.type element. check whether it is 1 (aka INT). %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %cmp_int, label %type_check_a_float cmp_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %ival_a_cast = bitcast %union.anon* %ival_a_ptr to i32* %ival_a = load i32* %ival_a_cast, align 4 ; get new_elem_b.ival that contains the casted integer value %ival_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %ival_b_cast = bitcast %union.anon* %ival_b_ptr to i32* %ival_b = load i32* %ival_b_cast, align 4 ; the actual comparison %equal_int = icmp eq i32 %ival_a, %ival_b br i1 %equal_int, label %exit_with_true, label %exit_with_false type_check_a_float: %ftype_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %ftype_a = load i32* %ftype_a_ptr, align 4 %is_float_a = icmp eq i32 %ftype_a, 2 br i1 %is_float_a, label %type_check_b_float, label %exit_with_invalid_type type_check_b_float: %ftype_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %ftype_b = load i32* %ftype_b_ptr, align 4 %is_float_b = icmp eq i32 %ftype_b, 2 br i1 %is_float_b, label %cmp_float, label %exit_with_invalid_type cmp_float: ; get new_elem_a.fval that contains the float value %fval_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %fval_a_cast = bitcast %union.anon* %fval_a_ptr to float* %fval_a = load float* %fval_a_cast, align 4 ; get new_elem_b.fval that contains the float value %fval_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %fval_b_cast = bitcast %union.anon* %fval_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 ; prevent division by zero %equal_float = fcmp oeq float %fval_a, %fval_b br i1 %equal_float, label %exit_with_true, label %exit_with_false exit_with_invalid_type: call void(i8*)* @push(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_true: call void(i8*)* @push(i8* getelementptr inbounds( [2 x i8]* @true, i64 0, i64 0)) br label %exit_with_success exit_with_false: call void(i8*)* @push(i8* getelementptr inbounds( [2 x i8]* @false, i64 0, i64 0)) br label %exit_with_success exit_with_failure: store i32 -1, i32* %func_result br label %exit exit_with_success: store i32 0, i32* %func_result br label %exit exit: %result = load i32* %func_result ret i32 %result } ;############################################################################## ; greater ;############################################################################## define i32 @greater(){ ; return value of this function %func_result = alloca i32, align 4 %new_elem_a = alloca %struct.stack_elem, align 8 %new_elem_b = alloca %struct.stack_elem, align 8 ; get top call void @underflow_assert() %number_a = call i8* @pop() ; get top-1 call void @underflow_assert() %number_b = call i8* @pop() ; get type of number_a %ret_a = call i32 @get_stack_elem(i8* %number_a, %struct.stack_elem* %new_elem_a) %is_zero_a = icmp slt i32 %ret_a, 0 br i1 %is_zero_a, label %exit_with_failure, label %get_type_b get_type_b: ; get type of number_b %ret_b = call i32 @get_stack_elem(i8* %number_b, %struct.stack_elem* %new_elem_b) %is_zero_b = icmp slt i32 %ret_b, 0 br i1 %is_zero_b, label %exit_with_failure, label %type_check_a_int type_check_a_int: ; first, load the new_elem_a.type element. check whether it is 1 (aka INT). %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %is_int_a = icmp eq i32 %type_a, 1 br i1 %is_int_a, label %type_check_b_int, label %type_check_a_float type_check_b_int: ; first, load the new_elem_b.type element. check whether it is 1 (aka INT). %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %cmp_int, label %type_check_a_float cmp_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %ival_a_cast = bitcast %union.anon* %ival_a_ptr to i32* %ival_a = load i32* %ival_a_cast, align 4 ; get new_elem_b.ival that contains the casted integer value %ival_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %ival_b_cast = bitcast %union.anon* %ival_b_ptr to i32* %ival_b = load i32* %ival_b_cast, align 4 ; the actual comparison %greater_int = icmp sgt i32 %ival_a, %ival_b br i1 %greater_int, label %exit_with_true, label %exit_with_false type_check_a_float: %ftype_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %ftype_a = load i32* %ftype_a_ptr, align 4 %is_float_a = icmp eq i32 %ftype_a, 2 br i1 %is_float_a, label %type_check_b_float, label %exit_with_invalid_type type_check_b_float: %ftype_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %ftype_b = load i32* %ftype_b_ptr, align 4 %is_float_b = icmp eq i32 %ftype_b, 2 br i1 %is_float_b, label %cmp_float, label %exit_with_invalid_type cmp_float: ; get new_elem_a.fval that contains the float value %fval_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 %fval_a_cast = bitcast %union.anon* %fval_a_ptr to float* %fval_a = load float* %fval_a_cast, align 4 ; get new_elem_b.fval that contains the float value %fval_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 %fval_b_cast = bitcast %union.anon* %fval_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 ; prevent division by zero %greater_float = fcmp ogt float %fval_a, %fval_b br i1 %greater_float, label %exit_with_true, label %exit_with_false exit_with_invalid_type: call void(i8*)* @push(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_true: call void(i8*)* @push(i8* getelementptr inbounds( [2 x i8]* @true, i64 0, i64 0)) br label %exit_with_success exit_with_false: call void(i8*)* @push(i8* getelementptr inbounds( [2 x i8]* @false, i64 0, i64 0)) br label %exit_with_success exit_with_failure: store i32 -1, i32* %func_result br label %exit exit_with_success: store i32 0, i32* %func_result br label %exit exit: %result = load i32* %func_result ret i32 %result } ; Popping a pointer from the stack into a variable define void @pop_into(i8** %var_ptr) { call void @underflow_assert() %val_ptr = call i8* @pop() store i8* %val_ptr, i8** %var_ptr ret void } ; Pushing a pointer from a variable onto the stack define void @push_from(i8** %var_ptr) { %val = load i8** %var_ptr call void @push (i8* %val) ret void } ; Function Attrs: nounwind uwtable ; Takes a string, determines the type it is representing and returns the ; corresponding stack element structure. define i32 @get_stack_elem(i8* %string, %struct.stack_elem* %elem) #0 { %1 = alloca i32, align 4 %2 = alloca i8*, align 8 %3 = alloca %struct.stack_elem*, align 8 %pEnd = alloca i8*, align 8 %new_long = alloca i64, align 8 %new_float = alloca float, align 4 store i8* %string, i8** %2, align 8 store %struct.stack_elem* %elem, %struct.stack_elem** %3, align 8 %4 = load i8** %2, align 8 %5 = call i64 @strtol(i8* %4, i8** %pEnd, i32 10) #2 store i64 %5, i64* %new_long, align 8 %6 = load i8** %pEnd, align 8 %7 = load i8* %6, align 1 %8 = sext i8 %7 to i32 %9 = icmp eq i32 %8, 0 br i1 %9, label %10, label %18 ;