; Module : LLVM backend - general math functions ; Description : Contains LLVM functions for mathematical operations like addition etc. ; Maintainers : Sascha Zinke ; License : MIT ; ; These functions are used by our LLVM backend and operate directly on the stack -- ; see stack.ll. @err_numeric = external global [56 x i8] @err_type = external global [14 x i8] @err_zero = external global [18 x i8] @popped = external global [13 x i8] %stack_element = type opaque %struct.stack_elem = type { i32, %union.anon } %union.anon = type { i8* } declare i8* @stack_element_get_data(%stack_element* %element) declare void @stack_element_unref(%stack_element* %element) declare i32 @get_stack_elem(i8*, %struct.stack_elem*) declare %stack_element* @push_string_ptr(i8* %str) declare %stack_element* @push_string_cpy(i8* %str) declare %stack_element* @pop_struct() declare signext i32 @printf(i8*, ...) declare void @push_float(double) declare void @underflow_assert() declare void @push_int(i64) declare i8* @pop_string() declare void @crash(i1) @main.number_b = private unnamed_addr constant [4 x i8] c"3.0\00" @main.number_a = private unnamed_addr constant [4 x i8] c"0.0\00" define i32 @main_math() { ; 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 %stack_element* @push_string_cpy(i8* %number0) call %stack_element* @push_string_cpy(i8* %number1) call i32 @div() %result = call i8* @pop_string() call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([13 x i8]* @popped, i32 0, i32 0), i8* %result) ret i32 0 } 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() %struct_a = call %stack_element*()* @pop_struct() %number_a = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_a) ; get second top of stack call void @underflow_assert() %struct_b = call %stack_element*()* @pop_struct() %number_b = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_b) ; 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_numeric_failure, label %get_stack_elem_b get_stack_elem_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_numeric_failure, label %get_types get_types: ; type of a %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %val_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 ; type of b %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %val_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 switch i32 %type_a, label %exit_with_invalid_type [ i32 1, label %assume_b_int i32 2, label %assume_b_float] ;############################################################################## ; integer multiplication ;############################################################################## assume_b_int: ; check whether it is 1 (aka INT). %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %mult_int, label %exit_with_invalid_type mult_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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 ;############################################################################## assume_b_float: ; check whether it is 2 (aka FLOAT). %is_float_b = icmp eq i32 %type_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_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 %fval_b_d = fpext float %fval_b to double ; mult 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_numeric_failure: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [56 x i8]* @err_numeric, i64 0, i64 0)) br label %exit_with_failure exit_with_invalid_type: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) call void @crash(i1 0) br label %exit exit: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) %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() %struct_a = call %stack_element*()* @pop_struct() %number_a = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_a) ; get second top of stack call void @underflow_assert() %struct_b = call %stack_element*()* @pop_struct() %number_b = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_b) ; 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_numeric_failure, label %get_stack_elem_b get_stack_elem_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_numeric_failure, label %get_types get_types: ; type of a %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %val_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 ; type of b %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %val_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 switch i32 %type_a, label %exit_with_invalid_type [ i32 1, label %assume_b_int i32 2, label %assume_b_float] ;############################################################################## ; integer remainder ;############################################################################## assume_b_int: %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %rem_int, label %exit_with_invalid_type rem_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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 ;############################################################################## assume_b_float: %is_float_b = icmp eq i32 %type_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_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_b_ptr to float* %fval_b = load float* %fval_b_cast, align 4 %fval_b_d = fpext float %fval_b to double ; rem 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_numeric_failure: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [56 x i8]* @err_numeric, i64 0, i64 0)) br label %exit_with_failure exit_with_invalid_type: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) call void @crash(i1 0) br label %exit exit: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) %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() %struct_b = call %stack_element*()* @pop_struct() %number_b = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_b) ; get second top of stack call void @underflow_assert() %struct_a = call %stack_element*()* @pop_struct() %number_a = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_a) ; 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_numeric_failure, label %get_stack_elem_b get_stack_elem_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_numeric_failure, label %get_types get_types: ; type of a %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %val_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 ; type of b %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %val_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 switch i32 %type_a, label %exit_with_invalid_type [ i32 1, label %assume_b_int i32 2, label %assume_b_float] ;############################################################################## ; integer subtraction ;############################################################################## assume_b_int: %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %sub_int, label %exit_with_invalid_type sub_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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 ;############################################################################## assume_b_float: %is_float_b = icmp eq i32 %type_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_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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_numeric_failure: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [56 x i8]* @err_numeric, i64 0, i64 0)) br label %exit_with_failure exit_with_invalid_type: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) call void @crash(i1 0) br label %exit exit: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) %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() %struct_a = call %stack_element*()* @pop_struct() %number_a = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_a) ; get second top of stack call void @underflow_assert() %struct_b = call %stack_element*()* @pop_struct() %number_b = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_b) ; 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_numeric_failure, label %get_stack_elem_b get_stack_elem_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_numeric_failure, label %get_types get_types: ; type of a %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %val_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 ; type of b %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %val_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 switch i32 %type_a, label %exit_with_invalid_type [ i32 1, label %assume_b_int i32 2, label %assume_b_float] ;############################################################################## ; integer addition ;############################################################################## assume_b_int: %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %add_int, label %exit_with_invalid_type add_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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 ;############################################################################## assume_b_float: %is_float_b = icmp eq i32 %type_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_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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_numeric_failure: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [56 x i8]* @err_numeric, i64 0, i64 0)) br label %exit_with_failure exit_with_invalid_type: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) call void @crash(i1 0) br label %exit exit_with_success: store i32 0, i32* %func_result br label %exit exit: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) %result = load i32* %func_result ret i32 %result } 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() %struct_b = call %stack_element*()* @pop_struct() %number_b = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_b) ; get second top of stack call void @underflow_assert() %struct_a = call %stack_element*()* @pop_struct() %number_a = call i8*(%stack_element*)* @stack_element_get_data( %stack_element* %struct_a) ; 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_numeric_failure, label %get_stack_elem_b get_stack_elem_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_numeric_failure, label %get_types get_types: ; type of a %type_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 0 %type_a = load i32* %type_a_ptr, align 4 %val_a_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_a, i32 0, i32 1 ; type of b %type_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 0 %type_b = load i32* %type_b_ptr, align 4 %val_b_ptr = getelementptr inbounds %struct.stack_elem* %new_elem_b, i32 0, i32 1 switch i32 %type_a, label %exit_with_invalid_type [ i32 1, label %assume_b_int i32 2, label %assume_b_float] ;############################################################################## ; integer division ;############################################################################## assume_b_int: %is_int_b = icmp eq i32 %type_b, 1 br i1 %is_int_b, label %div_int, label %exit_with_invalid_type div_int: ; get new_elem_a.ival that contains the casted integer value %ival_a_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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 ;############################################################################## assume_b_float: %is_float_b = icmp eq i32 %type_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_cast = bitcast %union.anon* %val_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_cast = bitcast %union.anon* %val_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_numeric_failure: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [56 x i8]* @err_numeric, i64 0, i64 0)) br label %exit_with_failure exit_with_zero: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [18 x i8]* @err_zero, i64 0, i64 0)) br label %exit_with_failure exit_with_invalid_type: call %stack_element* @push_string_cpy(i8* getelementptr inbounds( [14 x i8]* @err_type, i64 0, i64 0)) br label %exit_with_failure exit_with_failure: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) call void @crash(i1 0) br label %exit exit: call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_a) call void(%stack_element*)* @stack_element_unref(%stack_element* %struct_b) %result = load i32* %func_result ret i32 %result }