; 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
}