TC-L Samples

Note

Starting from a typed AST, generate the LLVM IR instructions using the LLVM framework.

Note

The TC reference implementation defines additional runtime functions. Additional primitives may therefore be declared, and the examples provided using --llvm-runtime-display may differ.

the-answer-llvm.tig
let
  var answer := 42
in
  answer := 51
end
tc --llvm-display the-answer-llvm.tig
$ tc --llvm-display the-answer-llvm.tig
; ModuleID = 'tc'
source_filename = "tc"
target triple = "x86_64-unknown-linux-gnu"

declare ptr addrspace(1) @tc_malloc(i64)

; Function Attrs: inlinehint nounwind
declare void @tc_print(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_err(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_int(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_flush() #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_getchar() #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_ord(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_chr(i64) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_size(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_streq(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_strcmp(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_substring(ptr addrspace(1), i64, i64) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_concat(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_not(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_exit(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_enable(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_run() #0

; Function Attrs: nounwind
define void @tc_main() #1 {
entry__main:
  %answer_18 = alloca i64, align 8
  store i64 42, ptr %answer_18, align 4
  store i64 51, ptr %answer_18, align 4
  ret void
}

attributes #0 = { inlinehint nounwind }
attributes #1 = { nounwind }
$ echo $?
0
add-llvm.tig
let
  function add(x: int, y: int) : int = x + y
in
  print_int(add(1,(add(2, 3)))); print("\n")
end
tc --llvm-display add-llvm.tig
$ tc --llvm-display add-llvm.tig
; ModuleID = 'tc'
source_filename = "tc"
target triple = "x86_64-unknown-linux-gnu"

@string = private unnamed_addr addrspace(1) constant [2 x i8] c"\0A\00", align 1

declare ptr addrspace(1) @tc_malloc(i64)

; Function Attrs: inlinehint nounwind
declare void @tc_print(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_err(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_int(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_flush() #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_getchar() #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_ord(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_chr(i64) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_size(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_streq(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_strcmp(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_substring(ptr addrspace(1), i64, i64) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_concat(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_not(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_exit(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_enable(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_run() #0

; Function Attrs: nounwind
define void @tc_main() #1 {
entry__main:
  %call_add_20 = call i64 @add_20(i64 2, i64 3)
  %call_add_201 = call i64 @add_20(i64 1, i64 %call_add_20)
  call void @tc_print_int(i64 %call_add_201)
  call void @tc_print(ptr addrspace(1) @string)
  ret void
}

; Function Attrs: nounwind
define internal i64 @add_20(i64 %x_18, i64 %y_19) #1 {
entry_add_20:
  %y_192 = alloca i64, align 8
  %x_181 = alloca i64, align 8
  store i64 %x_18, ptr %x_181, align 4
  store i64 %y_19, ptr %y_192, align 4
  %x_183 = load i64, ptr %x_181, align 4
  %y_194 = load i64, ptr %y_192, align 4
  %addtmp = add i64 %x_183, %y_194
  ret i64 %addtmp
}

attributes #0 = { inlinehint nounwind }
attributes #1 = { nounwind }
$ echo $?
0

Note

Once your compiler is complete, you can produce an actual LLVM IR output and compile it with Clang to produce a real executable program.

tc --llvm-runtime-display --llvm-display add-llvm.tig
$ tc --llvm-runtime-display --llvm-display add-llvm.tig
; ModuleID = 'tc'
source_filename = "tc"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@string = private unnamed_addr addrspace(1) constant [2 x i8] c"\0A\00", align 1
@tc_malloc.msg = internal constant [26 x i8] c"malloc: memory exhausted\0A\00", align 16
@stderr = external global ptr, align 8
@.str = private unnamed_addr constant [29 x i8] c"chr: character out of range\0A\00", align 1
@consts = internal global [512 x i8] zeroinitializer, align 16
@.str.1 = private unnamed_addr constant [36 x i8] c"substring: arguments out of bounds\0A\00", align 1
@stdin = external global ptr, align 8
@.str.2 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
@.str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@.str.4 = private unnamed_addr constant [4 x i8] c"%ld\00", align 1
@stdout = external global ptr, align 8

; Function Attrs: inlinehint nounwind
declare void @tc_gc_enable(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_run() #0

; Function Attrs: nounwind
define void @tc_main() #1 {
entry__main:
  %call_add_20 = call i64 @add_20(i64 2, i64 3)
  %call_add_201 = call i64 @add_20(i64 1, i64 %call_add_20)
  call void @tc_print_int(i64 %call_add_201)
  call void @tc_print(ptr addrspace(1) @string)
  ret void
}

; Function Attrs: nounwind
define internal i64 @add_20(i64 %x_18, i64 %y_19) #1 {
entry_add_20:
  %y_192 = alloca i64, align 8
  %x_181 = alloca i64, align 8
  store i64 %x_18, ptr %x_181, align 4
  store i64 %y_19, ptr %y_192, align 4
  %x_183 = load i64, ptr %x_181, align 4
  %y_194 = load i64, ptr %y_192, align 4
  %addtmp = add i64 %x_183, %y_194
  ret i64 %addtmp
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local void @local_roots_push(i64 noundef %0, ptr noundef %1) #2 {
  %3 = alloca i64, align 8
  %4 = alloca ptr, align 8
  store i64 %0, ptr %3, align 8
  store ptr %1, ptr %4, align 8
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local void @local_roots_pop(ptr noundef %0) #2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local void @gc_enter_runtime(ptr noundef %0, ptr noundef %1) #2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8
  store ptr %1, ptr %4, align 8
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local void @gc_exit_runtime(ptr noundef %0) #2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local ptr @tc_malloc(i64 noundef %0) #2 {
  %2 = alloca i64, align 8
  %3 = alloca ptr, align 8
  store i64 %0, ptr %2, align 8
  %4 = load i64, ptr %2, align 8
  %5 = call noalias ptr @malloc(i64 noundef %4) #9
  store ptr %5, ptr %3, align 8
  %6 = load ptr, ptr %3, align 8
  %7 = icmp eq ptr %6, null
  br i1 %7, label %8, label %11

8:                                                ; preds = %1
  %9 = load ptr, ptr @stderr, align 8
  %10 = call i64 @fwrite(ptr noundef @tc_malloc.msg, i64 noundef 1, i64 noundef 25, ptr noundef %9)
  call void @exit(i32 noundef 120) #10
  unreachable

11:                                               ; preds = %1
  %12 = load ptr, ptr %3, align 8
  %13 = load i64, ptr %2, align 8
  call void @llvm.memset.p0.i64(ptr align 1 %12, i8 0, i64 %13, i1 false)
  %14 = load ptr, ptr %3, align 8
  ret ptr %14
}

; Function Attrs: nounwind allocsize(0)
declare noalias ptr @malloc(i64 noundef) #3

declare i64 @fwrite(ptr noundef, i64 noundef, i64 noundef, ptr noundef) #4

; Function Attrs: noreturn nounwind
declare void @exit(i32 noundef) #5

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #6

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local ptr @tc_init_array(i64 noundef %0, i64 noundef %1) #2 {
  %3 = alloca i64, align 8
  %4 = alloca i64, align 8
  %5 = alloca ptr, align 8
  %6 = alloca i64, align 8
  store i64 %0, ptr %3, align 8
  store i64 %1, ptr %4, align 8
  %7 = load i64, ptr %3, align 8
  %8 = mul i64 %7, 8
  %9 = call ptr @tc_malloc(i64 noundef %8)
  store ptr %9, ptr %5, align 8
  store i64 0, ptr %6, align 8
  br label %10

10:                                               ; preds = %19, %2
  %11 = load i64, ptr %6, align 8
  %12 = load i64, ptr %3, align 8
  %13 = icmp ult i64 %11, %12
  br i1 %13, label %14, label %22

14:                                               ; preds = %10
  %15 = load i64, ptr %4, align 8
  %16 = load ptr, ptr %5, align 8
  %17 = load i64, ptr %6, align 8
  %18 = getelementptr inbounds i64, ptr %16, i64 %17
  store i64 %15, ptr %18, align 8
  br label %19

19:                                               ; preds = %14
  %20 = load i64, ptr %6, align 8
  %21 = add i64 %20, 1
  store i64 %21, ptr %6, align 8
  br label %10

22:                                               ; preds = %10
  %23 = load ptr, ptr %5, align 8
  ret ptr %23
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local ptr @tc_init_ptr_array(i64 noundef %0, i64 noundef %1) #2 {
  %3 = alloca i64, align 8
  %4 = alloca i64, align 8
  store i64 %0, ptr %3, align 8
  store i64 %1, ptr %4, align 8
  %5 = load i64, ptr %3, align 8
  %6 = load i64, ptr %4, align 8
  %7 = call ptr @tc_init_array(i64 noundef %5, i64 noundef %6)
  ret ptr %7
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local ptr @tc_init_string(i64 noundef %0) #2 {
  %2 = alloca i64, align 8
  store i64 %0, ptr %2, align 8
  %3 = load i64, ptr %2, align 8
  %4 = call ptr @tc_malloc(i64 noundef %3)
  ret ptr %4
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i64 @tc_not(i64 noundef %0) #2 {
  %2 = alloca i64, align 8
  store i64 %0, ptr %2, align 8
  %3 = load i64, ptr %2, align 8
  %4 = icmp ne i64 %3, 0
  %5 = xor i1 %4, true
  %6 = zext i1 %5 to i32
  %7 = sext i32 %6 to i64
  ret i64 %7
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @tc_exit(i64 noundef %0) #2 {
  %2 = alloca i64, align 8
  store i64 %0, ptr %2, align 8
  %3 = load i64, ptr %2, align 8
  %4 = trunc i64 %3 to i32
  call void @exit(i32 noundef %4) #10
  unreachable
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local ptr @tc_chr(i64 noundef %0) #2 {
  %2 = alloca i64, align 8
  store i64 %0, ptr %2, align 8
  %3 = load i64, ptr %2, align 8
  %4 = icmp sle i64 0, %3
  br i1 %4, label %5, label %8

5:                                                ; preds = %1
  %6 = load i64, ptr %2, align 8
  %7 = icmp sle i64 %6, 255
  br i1 %7, label %11, label %8

8:                                                ; preds = %5, %1
  %9 = load ptr, ptr @stderr, align 8
  %10 = call i32 @fputs(ptr noundef @.str, ptr noundef %9)
  call void @exit(i32 noundef 120) #10
  unreachable

11:                                               ; preds = %5
  %12 = load i64, ptr %2, align 8
  %13 = mul nsw i64 %12, 2
  %14 = getelementptr inbounds i8, ptr @consts, i64 %13
  ret ptr %14
}

declare i32 @fputs(ptr noundef, ptr noundef) #4

; Function Attrs: noinline nounwind optnone uwtable
define dso_local ptr @tc_concat(ptr noundef %0, ptr noundef %1) #2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  %5 = alloca ptr, align 8
  %6 = alloca ptr, align 8
  %7 = alloca ptr, align 8
  %8 = alloca [2 x ptr], align 8
  %9 = alloca i64, align 8
  %10 = alloca i64, align 8
  %11 = alloca i32, align 4
  %12 = alloca i64, align 8
  %13 = alloca i64, align 8
  %14 = alloca ptr, align 8
  %15 = alloca ptr, align 8
  %16 = alloca [1 x ptr], align 8
  store ptr %0, ptr %4, align 8
  store ptr %1, ptr %5, align 8
  %17 = call ptr @llvm.returnaddress(i32 0)
  %18 = call ptr @llvm.frameaddress.p0(i32 1)
  call void @gc_enter_runtime(ptr noundef %17, ptr noundef %18)
  %19 = getelementptr inbounds [2 x ptr], ptr %8, i64 0, i64 0
  store ptr %4, ptr %19, align 8
  %20 = getelementptr inbounds ptr, ptr %19, i64 1
  store ptr %5, ptr %20, align 8
  %21 = getelementptr inbounds [2 x ptr], ptr %8, i64 0, i64 0
  store ptr %21, ptr %7, align 8
  %22 = load ptr, ptr %7, align 8
  call void @local_roots_push(i64 noundef 2, ptr noundef %22)
  %23 = load ptr, ptr %4, align 8
  %24 = call i64 @strlen(ptr noundef %23) #11
  store i64 %24, ptr %9, align 8
  %25 = load ptr, ptr %5, align 8
  %26 = call i64 @strlen(ptr noundef %25) #11
  store i64 %26, ptr %10, align 8
  %27 = load i64, ptr %9, align 8
  %28 = icmp eq i64 %27, 0
  br i1 %28, label %29, label %31

29:                                               ; preds = %2
  %30 = load ptr, ptr %5, align 8
  store ptr %30, ptr %3, align 8
  store i32 1, ptr %11, align 4
  br label %84

31:                                               ; preds = %2
  %32 = load i64, ptr %10, align 8
  %33 = icmp eq i64 %32, 0
  br i1 %33, label %34, label %36

34:                                               ; preds = %31
  %35 = load ptr, ptr %4, align 8
  store ptr %35, ptr %3, align 8
  store i32 1, ptr %11, align 4
  br label %84

36:                                               ; preds = %31
  store i64 0, ptr %12, align 8
  %37 = load i64, ptr %9, align 8
  %38 = load i64, ptr %10, align 8
  %39 = add i64 %37, %38
  store i64 %39, ptr %13, align 8
  %40 = load i64, ptr %13, align 8
  %41 = add i64 %40, 1
  %42 = call ptr @tc_init_string(i64 noundef %41)
  store ptr %42, ptr %14, align 8
  %43 = getelementptr inbounds [1 x ptr], ptr %16, i64 0, i64 0
  store ptr %14, ptr %43, align 8
  %44 = getelementptr inbounds [1 x ptr], ptr %16, i64 0, i64 0
  store ptr %44, ptr %15, align 8
  %45 = load ptr, ptr %15, align 8
  call void @local_roots_push(i64 noundef 1, ptr noundef %45)
  store i64 0, ptr %12, align 8
  br label %46

46:                                               ; preds = %58, %36
  %47 = load i64, ptr %12, align 8
  %48 = load i64, ptr %9, align 8
  %49 = icmp ult i64 %47, %48
  br i1 %49, label %50, label %61

50:                                               ; preds = %46
  %51 = load ptr, ptr %4, align 8
  %52 = load i64, ptr %12, align 8
  %53 = getelementptr inbounds i8, ptr %51, i64 %52
  %54 = load i8, ptr %53, align 1
  %55 = load ptr, ptr %14, align 8
  %56 = load i64, ptr %12, align 8
  %57 = getelementptr inbounds i8, ptr %55, i64 %56
  store i8 %54, ptr %57, align 1
  br label %58

58:                                               ; preds = %50
  %59 = load i64, ptr %12, align 8
  %60 = add i64 %59, 1
  store i64 %60, ptr %12, align 8
  br label %46

61:                                               ; preds = %46
  store i64 0, ptr %12, align 8
  br label %62

62:                                               ; preds = %76, %61
  %63 = load i64, ptr %12, align 8
  %64 = load i64, ptr %10, align 8
  %65 = icmp ult i64 %63, %64
  br i1 %65, label %66, label %79

66:                                               ; preds = %62
  %67 = load ptr, ptr %5, align 8
  %68 = load i64, ptr %12, align 8
  %69 = getelementptr inbounds i8, ptr %67, i64 %68
  %70 = load i8, ptr %69, align 1
  %71 = load ptr, ptr %14, align 8
  %72 = load i64, ptr %12, align 8
  %73 = load i64, ptr %9, align 8
  %74 = add i64 %72, %73
  %75 = getelementptr inbounds i8, ptr %71, i64 %74
  store i8 %70, ptr %75, align 1
  br label %76

76:                                               ; preds = %66
  %77 = load i64, ptr %12, align 8
  %78 = add i64 %77, 1
  store i64 %78, ptr %12, align 8
  br label %62

79:                                               ; preds = %62
  %80 = load ptr, ptr %14, align 8
  %81 = load i64, ptr %13, align 8
  %82 = getelementptr inbounds i8, ptr %80, i64 %81
  store i8 0, ptr %82, align 1
  %83 = load ptr, ptr %14, align 8
  store ptr %83, ptr %3, align 8
  store i32 1, ptr %11, align 4
  call void @local_roots_pop(ptr noundef %15)
  br label %84

84:                                               ; preds = %79, %34, %29
  call void @local_roots_pop(ptr noundef %7)
  call void @gc_exit_runtime(ptr noundef %6)
  %85 = load ptr, ptr %3, align 8
  ret ptr %85
}

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
declare ptr @llvm.returnaddress(i32 immarg) #7

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
declare ptr @llvm.frameaddress.p0(i32 immarg) #7

; Function Attrs: nounwind willreturn memory(read)
declare i64 @strlen(ptr noundef) #8

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i64 @tc_ord(ptr noundef %0) #2 {
  %2 = alloca i64, align 8
  %3 = alloca ptr, align 8
  %4 = alloca i64, align 8
  store ptr %0, ptr %3, align 8
  %5 = load ptr, ptr %3, align 8
  %6 = call i64 @strlen(ptr noundef %5) #11
  store i64 %6, ptr %4, align 8
  %7 = load i64, ptr %4, align 8
  %8 = icmp eq i64 %7, 0
  br i1 %8, label %9, label %10

9:                                                ; preds = %1
  store i64 -1, ptr %2, align 8
  br label %15

10:                                               ; preds = %1
  %11 = load ptr, ptr %3, align 8
  %12 = getelementptr inbounds i8, ptr %11, i64 0
  %13 = load i8, ptr %12, align 1
  %14 = sext i8 %13 to i64
  store i64 %14, ptr %2, align 8
  br label %15

15:                                               ; preds = %10, %9
  %16 = load i64, ptr %2, align 8
  ret i64 %16
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i64 @tc_size(ptr noundef %0) #2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  %3 = load ptr, ptr %2, align 8
  %4 = call i64 @strlen(ptr noundef %3) #11
  ret i64 %4
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local ptr @tc_substring(ptr noundef %0, i64 noundef %1, i64 noundef %2) #2 {
  %4 = alloca ptr, align 8
  %5 = alloca ptr, align 8
  %6 = alloca i64, align 8
  %7 = alloca i64, align 8
  %8 = alloca ptr, align 8
  %9 = alloca ptr, align 8
  %10 = alloca [1 x ptr], align 8
  %11 = alloca i64, align 8
  %12 = alloca i32, align 4
  %13 = alloca ptr, align 8
  %14 = alloca ptr, align 8
  %15 = alloca [1 x ptr], align 8
  %16 = alloca i32, align 4
  store ptr %0, ptr %5, align 8
  store i64 %1, ptr %6, align 8
  store i64 %2, ptr %7, align 8
  %17 = call ptr @llvm.returnaddress(i32 0)
  %18 = call ptr @llvm.frameaddress.p0(i32 1)
  call void @gc_enter_runtime(ptr noundef %17, ptr noundef %18)
  %19 = getelementptr inbounds [1 x ptr], ptr %10, i64 0, i64 0
  store ptr %5, ptr %19, align 8
  %20 = getelementptr inbounds [1 x ptr], ptr %10, i64 0, i64 0
  store ptr %20, ptr %9, align 8
  %21 = load ptr, ptr %9, align 8
  call void @local_roots_push(i64 noundef 1, ptr noundef %21)
  %22 = load ptr, ptr %5, align 8
  %23 = call i64 @strlen(ptr noundef %22) #11
  store i64 %23, ptr %11, align 8
  %24 = load i64, ptr %6, align 8
  %25 = icmp sle i64 0, %24
  br i1 %25, label %26, label %35

26:                                               ; preds = %3
  %27 = load i64, ptr %7, align 8
  %28 = icmp sle i64 0, %27
  br i1 %28, label %29, label %35

29:                                               ; preds = %26
  %30 = load i64, ptr %6, align 8
  %31 = load i64, ptr %7, align 8
  %32 = add nsw i64 %30, %31
  %33 = load i64, ptr %11, align 8
  %34 = icmp ule i64 %32, %33
  br i1 %34, label %38, label %35

35:                                               ; preds = %29, %26, %3
  %36 = load ptr, ptr @stderr, align 8
  %37 = call i32 @fputs(ptr noundef @.str.1, ptr noundef %36)
  call void @exit(i32 noundef 120) #10
  unreachable

38:                                               ; preds = %29
  %39 = load i64, ptr %7, align 8
  %40 = icmp eq i64 %39, 1
  br i1 %40, label %41, label %50

41:                                               ; preds = %38
  %42 = load ptr, ptr %5, align 8
  %43 = load i64, ptr %6, align 8
  %44 = getelementptr inbounds i8, ptr %42, i64 %43
  %45 = load i8, ptr %44, align 1
  %46 = sext i8 %45 to i32
  %47 = mul nsw i32 %46, 2
  %48 = sext i32 %47 to i64
  %49 = getelementptr inbounds i8, ptr @consts, i64 %48
  store ptr %49, ptr %4, align 8
  store i32 1, ptr %12, align 4
  br label %82

50:                                               ; preds = %38
  %51 = load i64, ptr %7, align 8
  %52 = add nsw i64 %51, 1
  %53 = call ptr @tc_init_string(i64 noundef %52)
  store ptr %53, ptr %13, align 8
  %54 = getelementptr inbounds [1 x ptr], ptr %15, i64 0, i64 0
  store ptr %13, ptr %54, align 8
  %55 = getelementptr inbounds [1 x ptr], ptr %15, i64 0, i64 0
  store ptr %55, ptr %14, align 8
  %56 = load ptr, ptr %14, align 8
  call void @local_roots_push(i64 noundef 1, ptr noundef %56)
  store i32 0, ptr %16, align 4
  br label %57

57:                                               ; preds = %74, %50
  %58 = load i32, ptr %16, align 4
  %59 = sext i32 %58 to i64
  %60 = load i64, ptr %7, align 8
  %61 = icmp slt i64 %59, %60
  br i1 %61, label %62, label %77

62:                                               ; preds = %57
  %63 = load ptr, ptr %5, align 8
  %64 = load i64, ptr %6, align 8
  %65 = load i32, ptr %16, align 4
  %66 = sext i32 %65 to i64
  %67 = add nsw i64 %64, %66
  %68 = getelementptr inbounds i8, ptr %63, i64 %67
  %69 = load i8, ptr %68, align 1
  %70 = load ptr, ptr %13, align 8
  %71 = load i32, ptr %16, align 4
  %72 = sext i32 %71 to i64
  %73 = getelementptr inbounds i8, ptr %70, i64 %72
  store i8 %69, ptr %73, align 1
  br label %74

74:                                               ; preds = %62
  %75 = load i32, ptr %16, align 4
  %76 = add nsw i32 %75, 1
  store i32 %76, ptr %16, align 4
  br label %57

77:                                               ; preds = %57
  %78 = load ptr, ptr %13, align 8
  %79 = load i64, ptr %7, align 8
  %80 = getelementptr inbounds i8, ptr %78, i64 %79
  store i8 0, ptr %80, align 1
  %81 = load ptr, ptr %13, align 8
  store ptr %81, ptr %4, align 8
  store i32 1, ptr %12, align 4
  call void @local_roots_pop(ptr noundef %14)
  br label %82

82:                                               ; preds = %77, %41
  call void @local_roots_pop(ptr noundef %9)
  call void @gc_exit_runtime(ptr noundef %8)
  %83 = load ptr, ptr %4, align 8
  ret ptr %83
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i64 @tc_strcmp(ptr noundef %0, ptr noundef %1) #2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8
  store ptr %1, ptr %4, align 8
  %5 = load ptr, ptr %3, align 8
  %6 = load ptr, ptr %4, align 8
  %7 = call i32 @strcmp(ptr noundef %5, ptr noundef %6) #11
  %8 = sext i32 %7 to i64
  ret i64 %8
}

; Function Attrs: nounwind willreturn memory(read)
declare i32 @strcmp(ptr noundef, ptr noundef) #8

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i64 @tc_streq(ptr noundef %0, ptr noundef %1) #2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8
  store ptr %1, ptr %4, align 8
  %5 = load ptr, ptr %3, align 8
  %6 = load ptr, ptr %4, align 8
  %7 = call i32 @strcmp(ptr noundef %5, ptr noundef %6) #11
  %8 = icmp eq i32 %7, 0
  %9 = zext i1 %8 to i32
  %10 = sext i32 %9 to i64
  ret i64 %10
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local ptr @tc_getchar() #2 {
  %1 = alloca ptr, align 8
  %2 = alloca i32, align 4
  %3 = load ptr, ptr @stdin, align 8
  %4 = call i32 @getc(ptr noundef %3)
  store i32 %4, ptr %2, align 4
  %5 = load i32, ptr %2, align 4
  %6 = icmp eq i32 %5, -1
  br i1 %6, label %7, label %8

7:                                                ; preds = %0
  store ptr @.str.2, ptr %1, align 8
  br label %13

8:                                                ; preds = %0
  %9 = load i32, ptr %2, align 4
  %10 = mul nsw i32 %9, 2
  %11 = sext i32 %10 to i64
  %12 = getelementptr inbounds i8, ptr @consts, i64 %11
  store ptr %12, ptr %1, align 8
  br label %13

13:                                               ; preds = %8, %7
  %14 = load ptr, ptr %1, align 8
  ret ptr %14
}

declare i32 @getc(ptr noundef) #4

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @tc_print(ptr noundef %0) #2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  %3 = load ptr, ptr %2, align 8
  %4 = call i32 (ptr, ...) @printf(ptr noundef @.str.3, ptr noundef %3)
  ret void
}

declare i32 @printf(ptr noundef, ...) #4

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @tc_print_err(ptr noundef %0) #2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  %3 = load ptr, ptr @stderr, align 8
  %4 = load ptr, ptr %2, align 8
  %5 = call i32 (ptr, ptr, ...) @fprintf(ptr noundef %3, ptr noundef @.str.3, ptr noundef %4)
  ret void
}

declare i32 @fprintf(ptr noundef, ptr noundef, ...) #4

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @tc_print_int(i64 noundef %0) #2 {
  %2 = alloca i64, align 8
  store i64 %0, ptr %2, align 8
  %3 = load i64, ptr %2, align 8
  %4 = call i32 (ptr, ...) @printf(ptr noundef @.str.4, i64 noundef %3)
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @tc_flush() #2 {
  %1 = load ptr, ptr @stdout, align 8
  %2 = call i32 @fflush(ptr noundef %1)
  ret void
}

declare i32 @fflush(ptr noundef) #4

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @init_consts() #2 {
  %1 = alloca i32, align 4
  store i32 0, ptr %1, align 4
  br label %2

2:                                                ; preds = %16, %0
  %3 = load i32, ptr %1, align 4
  %4 = icmp slt i32 %3, 512
  br i1 %4, label %5, label %19

5:                                                ; preds = %2
  %6 = load i32, ptr %1, align 4
  %7 = sdiv i32 %6, 2
  %8 = trunc i32 %7 to i8
  %9 = load i32, ptr %1, align 4
  %10 = sext i32 %9 to i64
  %11 = getelementptr inbounds [512 x i8], ptr @consts, i64 0, i64 %10
  store i8 %8, ptr %11, align 1
  %12 = load i32, ptr %1, align 4
  %13 = add nsw i32 %12, 1
  %14 = sext i32 %13 to i64
  %15 = getelementptr inbounds [512 x i8], ptr @consts, i64 0, i64 %14
  store i8 0, ptr %15, align 1
  br label %16

16:                                               ; preds = %5
  %17 = load i32, ptr %1, align 4
  %18 = add nsw i32 %17, 2
  store i32 %18, ptr %1, align 4
  br label %2

19:                                               ; preds = %2
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define weak dso_local i32 @main() #2 {
  %1 = alloca i32, align 4
  store i32 0, ptr %1, align 4
  call void @init_consts()
  call void @tc_main(i32 noundef 0)
  ret i32 0
}

attributes #0 = { inlinehint nounwind }
attributes #1 = { nounwind }
attributes #2 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #3 = { nounwind allocsize(0) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #4 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #5 = { noreturn nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #6 = { nocallback nofree nounwind willreturn memory(argmem: write) }
attributes #7 = { nocallback nofree nosync nounwind willreturn memory(none) }
attributes #8 = { nounwind willreturn memory(read) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #9 = { nounwind allocsize(0) }
attributes #10 = { noreturn nounwind }
attributes #11 = { nounwind willreturn memory(read) }

!llvm.ident = !{!0}
!llvm.module.flags = !{!1, !2, !3, !4, !5}

!0 = !{!"clang version 18.1.8"}
!1 = !{i32 1, !"wchar_size", i32 4}
!2 = !{i32 8, !"PIC Level", i32 2}
!3 = !{i32 7, !"PIE Level", i32 2}
!4 = !{i32 7, !"uwtable", i32 2}
!5 = !{i32 7, !"frame-pointer", i32 2}
$ echo $?
0
tc --llvm-runtime-display --llvm-display add-llvm.tig > add-llvm.ll
$ tc --llvm-runtime-display --llvm-display add-llvm.tig > add-llvm.ll

$ echo $?
0
clang -m64 -oadd-llvm add-llvm.ll
$ clang -m64 -oadd-llvm add-llvm.ll
clang: warning: argument unused during compilation: '-idirafter /nix/store/1v9ggwkpb0xy708s11s1g9fhinn3b06r-glibc-2.40-66-dev/include' [-Wunused-command-line-argument]
$ echo $?
0
./add-llvm
$ ./add-llvm
6
$ echo $?
0
if.tig
if 1
  then 1
  else 2
tc --llvm-display if.tig
$ tc --llvm-display if.tig
; ModuleID = 'tc'
source_filename = "tc"
target triple = "x86_64-unknown-linux-gnu"

declare ptr addrspace(1) @tc_malloc(i64)

; Function Attrs: inlinehint nounwind
declare void @tc_print(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_err(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_int(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_flush() #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_getchar() #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_ord(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_chr(i64) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_size(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_streq(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_strcmp(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_substring(ptr addrspace(1), i64, i64) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_concat(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_not(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_exit(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_enable(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_run() #0

; Function Attrs: nounwind
define void @tc_main() #1 {
entry__main:
  br i1 true, label %then, label %else

then:                                             ; preds = %entry__main
  br label %ifend

else:                                             ; preds = %entry__main
  br label %ifend

ifend:                                            ; preds = %else, %then
  %iftmp = phi i64 [ 1, %then ], [ 2, %else ]
  ret void
}

attributes #0 = { inlinehint nounwind }
attributes #1 = { nounwind }
$ echo $?
0
while.tig
while 1
do
  print("toto")
tc --llvm-display while.tig
$ tc --llvm-display while.tig
; ModuleID = 'tc'
source_filename = "tc"
target triple = "x86_64-unknown-linux-gnu"

@string = private unnamed_addr addrspace(1) constant [5 x i8] c"toto\00", align 1

declare ptr addrspace(1) @tc_malloc(i64)

; Function Attrs: inlinehint nounwind
declare void @tc_print(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_err(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_int(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_flush() #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_getchar() #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_ord(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_chr(i64) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_size(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_streq(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_strcmp(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_substring(ptr addrspace(1), i64, i64) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_concat(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_not(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_exit(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_enable(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_run() #0

; Function Attrs: nounwind
define void @tc_main() #1 {
entry__main:
  br label %test

test:                                             ; preds = %body, %entry__main
  br i1 true, label %body, label %afterloop

body:                                             ; preds = %test
  call void @tc_print(ptr addrspace(1) @string)
  br label %test

afterloop:                                        ; preds = %test
  ret void
}

attributes #0 = { inlinehint nounwind }
attributes #1 = { nounwind }
$ echo $?
0
array.tig
let
  type arrtype = array of int
  var arr1 : arrtype := arrtype [10] of 0
in
  arr1[2]
end
tc --llvm-display array.tig
$ tc --llvm-display array.tig
; ModuleID = 'tc'
source_filename = "tc"
target triple = "x86_64-unknown-linux-gnu"

declare ptr addrspace(1) @tc_malloc(i64)

; Function Attrs: inlinehint nounwind
declare void @tc_print(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_err(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_int(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_flush() #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_getchar() #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_ord(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_chr(i64) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_size(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_streq(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_strcmp(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_substring(ptr addrspace(1), i64, i64) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_concat(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_not(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_exit(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_enable(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_run() #0

; Function Attrs: nounwind
define void @tc_main() #1 {
entry__main:
  %arr1_19 = alloca ptr addrspace(1), align 8
  %init_array_call = call ptr addrspace(1) @tc_init_array(i64 10, i64 0)
  store ptr addrspace(1) %init_array_call, ptr %arr1_19, align 8
  %arr1_191 = load ptr addrspace(1), ptr %arr1_19, align 8
  %subscriptptr = getelementptr i64, ptr addrspace(1) %arr1_191, i64 2
  %subscriptvar = load i64, ptr addrspace(1) %subscriptptr, align 4
  ret void
}

declare ptr addrspace(1) @tc_init_array(i64, i64)

attributes #0 = { inlinehint nounwind }
attributes #1 = { nounwind }
$ echo $?
0
record.tig
/* a record type and a record variable */
let
  type  rectype = {name : string, age : int}
  var rec1 : rectype := rectype {name="Nobody", age=1000}
in
  rec1.name := "Somebody";
  rec1
end
tc --llvm-display record.tig
$ tc --llvm-display record.tig
; ModuleID = 'tc'
source_filename = "tc"
target triple = "x86_64-unknown-linux-gnu"

%0 = type { ptr addrspace(1), i64 }

@string = private unnamed_addr addrspace(1) constant [7 x i8] c"Nobody\00", align 1
@string.1 = private unnamed_addr addrspace(1) constant [9 x i8] c"Somebody\00", align 1

declare noalias ptr addrspace(1) @tc_malloc(i64)

; Function Attrs: inlinehint nounwind
declare void @tc_print(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_err(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare void @tc_print_int(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_flush() #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_getchar() #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_ord(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_chr(i64) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_size(ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_streq(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_strcmp(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_substring(ptr addrspace(1), i64, i64) #0

; Function Attrs: inlinehint nounwind
declare ptr addrspace(1) @tc_concat(ptr addrspace(1), ptr addrspace(1)) #0

; Function Attrs: inlinehint nounwind
declare i64 @tc_not(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_exit(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_enable(i64) #0

; Function Attrs: inlinehint nounwind
declare void @tc_gc_run() #0

; Function Attrs: nounwind
define void @tc_main() #1 {
entry__main:
  %rec1_19 = alloca ptr addrspace(1), align 8
  %malloccall = tail call ptr addrspace(1) @tc_malloc(i64 ptrtoint (ptr getelementptr (%0, ptr null, i32 1) to i64))
  %fieldinit_name = getelementptr inbounds %0, ptr addrspace(1) %malloccall, i32 0, i32 0
  store ptr addrspace(1) @string, ptr addrspace(1) %fieldinit_name, align 8
  %fieldinit_age = getelementptr inbounds %0, ptr addrspace(1) %malloccall, i32 0, i32 1
  store i64 1000, ptr addrspace(1) %fieldinit_age, align 4
  store ptr addrspace(1) %malloccall, ptr %rec1_19, align 8
  %rec1_191 = load ptr addrspace(1), ptr %rec1_19, align 8
  %fieldptr_name = getelementptr inbounds %0, ptr addrspace(1) %rec1_191, i32 0, i32 0
  store ptr addrspace(1) @string.1, ptr addrspace(1) %fieldptr_name, align 8
  %rec1_192 = load ptr addrspace(1), ptr %rec1_19, align 8
  ret void
}

attributes #0 = { inlinehint nounwind }
attributes #1 = { nounwind }
$ echo $?
0