packages feed

rail-compiler-editor-0.3.0.0: src/RailCompiler/math.ll

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