packages feed

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

; Module      : LLVM backend - string functions
; Description : Contains LLVM functions for operations on strings (e. g. concatenation).
; Maintainers : Maximilian Claus
; License     : MIT
;
; These functions are used by our LLVM backend and most of them operate
; directly on the stack -- see stack.ll.

@true = external global i8
@false = external global i8
@.str_err0 = unnamed_addr constant [41 x i8] c"Crash: strcut called with negative index\00"
@.str_err1 = unnamed_addr constant [58 x i8] c"Crash: strcut called with index larger than string length\00"
@strcut_neg_arg_err = global i8* getelementptr inbounds ([41 x i8]* @.str_err0, i64 0, i64 0), align 8
@strcut_too_large_arg_err = global i8* getelementptr inbounds ([58 x i8]* @.str_err1, i64 0, i64 0), align 8

; error handling
%FILE = type opaque
@stderr = external global %FILE*
declare signext i32 @fprintf(%FILE*, i8*, ...)
declare void @exit(i32 signext)

; stack functions
%stack_element = type opaque

declare void @underflow_assert()
declare %stack_element* @push_string_ptr(i8* %str)
declare %stack_element* @push_string_cpy(i8* %str)
declare void @push_int(i64)
declare %stack_element* @pop_struct()
declare void @stack_element_assert_type(%stack_element*, i8)
declare i8* @stack_element_get_data(%stack_element* %element)
declare i64 @stack_element_get_int_data(%stack_element* %element)
declare void @stack_element_unref(%stack_element* %element)

declare i8* @malloc(i16 zeroext) ; void *malloc(size_t) and size_t is 16 bits long (SIZE_MAX)

; TODO: free alloated space of input strings
define void @strapp() {
entry:
  call void @underflow_assert() 
  %elem2 = call %stack_element*()* @pop_struct()
  %str2 = call i8*(%stack_element*)* @stack_element_get_data(%stack_element* %elem2)
  call void @underflow_assert() 
  %elem1 = call %stack_element*()* @pop_struct()
  %str1 = call i8*(%stack_element*)* @stack_element_get_data(%stack_element* %elem1)

  ; compute length of input strings
  %len_str1 = call i64(i8*)* @length(i8* %str1)
  %len_str2 = call i64(i8*)* @length(i8* %str2)

  ; 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 into result
  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 into result
  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(%stack_element*)* @stack_element_unref(%stack_element* %elem2)
  call void(%stack_element*)* @stack_element_unref(%stack_element* %elem1)
  call %stack_element* @push_string_ptr(i8* %result)
  ret void
}

define i64 @length(i8* %str) {
entry:
  br label %loop
loop:
  %i = phi i64 [0, %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:
  ret i64 %i
}

define void @strlen() {
entry:  
  ; pop string
  call void @underflow_assert() 
  %elem = call %stack_element*()* @pop_struct()
  %str = call i8*(%stack_element*)* @stack_element_get_data(%stack_element* %elem)

  ; compute length
  %len = call i64(i8*)* @length(i8* %str)

  ; push length
  call void(%stack_element*)* @stack_element_unref(%stack_element* %elem)
  call void(i64)* @push_int(i64 %len)
  ret void
}

define void @strcut() {
entry:
  call void @underflow_assert()
  %elem2 = call %stack_element*()* @pop_struct()
  %indx = call i64(%stack_element*)* @stack_element_get_int_data(%stack_element* %elem2)

  call void @underflow_assert() 
  %elem1 = call %stack_element*()* @pop_struct()
  call void @stack_element_assert_type(%stack_element* %elem1, i8 0)
  %str = call i8*(%stack_element*)* @stack_element_get_data(%stack_element* %elem1)

  ; allocate space for result strings
  %len1_1 = add i64 %indx, 1
  %len1 = trunc i64 %len1_1 to i16
  %len_str = call i64(i8*)* @length(i8* %str) 
  %len2_1 = sub i64 %len_str, %indx
  %len2_2 = add i64 %len2_1, 1
  %len2 = trunc i64 %len2_2 to i16
  %result1 = call i8* @malloc(i16 %len1)
  %result2 = call i8* @malloc(i16 %len2)

  ; check whether index argument is within bounds
  %stderr = load %FILE** @stderr

  %err0 = icmp slt i64 %indx, 0
  br i1 %err0, label %neg_arg, label %continue_check
neg_arg:
  %err_msg0 = load i8** @strcut_neg_arg_err
  call i32(%FILE*, i8*, ...)* @fprintf(%FILE* %stderr, i8* %err_msg0)
  call void @exit(i32 1)
  ret void
continue_check:
  %err1 = icmp sgt i64 %indx, %len_str
  br i1 %err1, label %too_large_arg, label %loop1
too_large_arg:
  %err_msg1 = load i8** @strcut_too_large_arg_err
  call i32(%FILE*, i8*, ...)* @fprintf(%FILE* %stderr, i8* %err_msg1)
  call void @exit(i32 1)
  ret void

  ; fill result1 string
loop1:
  %i = phi i64 [0, %continue_check], [ %next_i, %loop1 ]
  %next_i = add i64 %i, 1
  %addr = getelementptr i8* %str, i64 %i
  %c = load i8* %addr
  %result_addr = getelementptr i8* %result1, i64 %i
  store i8 %c, i8* %result_addr
  %cond = icmp eq i64 %i, %indx
  br i1 %cond, label %finished, label %loop1
finished:
  %end_addr = getelementptr i8* %result1, i64 %indx
  store i8 0, i8* %end_addr
  ; fill result2 string
  br label %loop2
loop2:
  %j = phi i64 [0, %finished], [ %next_j, %loop2 ]
  %next_j = add i64 %j, 1
  %k = add i64 %j, %indx
  %addr2 = getelementptr i8* %str, i64 %k
  %c2 = load i8* %addr2
  %result_addr2 = getelementptr i8* %result2, i64 %j
  store i8 %c2, i8* %result_addr2
  %cond2 = icmp eq i8 %c2, 0
  br i1 %cond2, label %finished2, label %loop2
finished2: 
  call void(%stack_element*)* @stack_element_unref(%stack_element* %elem2)
  call void(%stack_element*)* @stack_element_unref(%stack_element* %elem1)
  call %stack_element* @push_string_ptr(i8* %result2)
  call %stack_element* @push_string_ptr(i8* %result1)
  ret void
}

; vim:sw=2 ts=2 et