diff --git a/src/llvm_emitter.odin b/src/llvm_emitter.odin index bf62040..c0cdb00 100644 --- a/src/llvm_emitter.odin +++ b/src/llvm_emitter.odin @@ -259,9 +259,53 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil } } - generate_llvm_scope :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuilderRef, function: LLVMValueRef, scope: ^Node, scope_number: ^i32) { + generate_llvm_if :: proc( + ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuilderRef, function: LLVMValueRef, + node: ^Node, scope_number: ^i32 + ) { + condition_node := node.children[0] + true_node := node.children[1] + false_node := node.children[2] + + bb := LLVMGetLastBasicBlock(function) + + condition := generate_llvm_expression(ctx, mod, builder, condition_node) + if condition == nil { + return + } + int_32_type := LLVMInt32TypeInContext(ctx) + comparison_res := LLVMBuildICmp(builder, .LLVMIntNE, condition, LLVMConstInt(int_32_type, 0, LLVMBool(1)), "") + + true_block := LLVMAppendBasicBlockInContext(ctx, function, "") + false_block := LLVMCreateBasicBlockInContext(ctx, "") + end_block := LLVMCreateBasicBlockInContext(ctx, "") + + cond_br := LLVMBuildCondBr(builder, comparison_res, true_block, false_block) + + LLVMPositionBuilderAtEnd(builder, true_block) + generate_llvm_scope(ctx, mod, builder, function, true_node, scope_number, true_block) + LLVMBuildBr(builder, end_block) + true_block = LLVMGetInsertBlock(builder) + + LLVMAppendExistingBasicBlock(function, false_block) + + LLVMPositionBuilderAtEnd(builder, false_block) + generate_llvm_scope(ctx, mod, builder, function, false_node, scope_number, false_block) + LLVMBuildBr(builder, end_block) + false_block = LLVMGetInsertBlock(builder) + + LLVMPositionBuilderAtEnd(builder, end_block) + LLVMAppendExistingBasicBlock(function, end_block) + } + + generate_llvm_scope :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuilderRef, function: LLVMValueRef, scope: ^Node, scope_number: ^i32, bb: LLVMBasicBlockRef = nil) { scope_name := get_basic_block_name(scope_number^) - basic_block := LLVMAppendBasicBlockInContext(ctx, function, scope_name) + basic_block : LLVMBasicBlockRef + if bb != nil { + basic_block = bb + } else { + basic_block = LLVMAppendBasicBlockInContext(ctx, function, scope_name) + } llvm_scope_enter(scope_name, basic_block) LLVMPositionBuilderAtEnd(builder, basic_block) scope_number^ += 1 @@ -289,6 +333,8 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil } llvm_top_scope().definitions[get_character_sum_of_dyn_arr(&node.children[0].value.([dynamic]u8))] = var llvm_top_scope().types[get_character_sum_of_dyn_arr(&node.children[0].value.([dynamic]u8))] = type + case .If: + generate_llvm_if(ctx, mod, builder, function, node, scope_number) case: panic("FIXME: Implement other node kinds") } diff --git a/src/llvmc.odin b/src/llvmc.odin index 6fb6afe..22f94ed 100644 --- a/src/llvmc.odin +++ b/src/llvmc.odin @@ -46,6 +46,19 @@ LLVMTypeKind :: enum { LLVMTargetExtTypeKind, } +LLVMIntPredicate :: enum { + LLVMIntEQ = 32, + LLVMIntNE, + LLVMIntUGT, + LLVMIntUGE, + LLVMIntULT, + LLVMIntULE, + LLVMIntSGT, + LLVMIntSGE, + LLVMIntSLT, + LLVMIntSLE, +} + @(default_calling_convention = "std") foreign llvmc { LLVMContextCreate :: proc() -> LLVMContextRef --- @@ -86,6 +99,11 @@ foreign llvmc { LLVMAddFunction :: proc(M: LLVMModuleRef, Name: cstring, FunctionType: LLVMTypeRef) -> LLVMValueRef --- LLVMAppendBasicBlockInContext :: proc(C: LLVMContextRef, Fn: LLVMValueRef, Name: cstring) -> LLVMBasicBlockRef --- + LLVMCreateBasicBlockInContext :: proc(C: LLVMContextRef, Name: cstring) -> LLVMBasicBlockRef --- + LLVMGetLastBasicBlock :: proc(Fn: LLVMValueRef) -> LLVMBasicBlockRef --- + LLVMGetInsertBlock :: proc(Builder: LLVMBuilderRef) -> LLVMBasicBlockRef --- + LLVMInsertExistingBasicBlockAfterInsertBlock :: proc(Builder: LLVMBuilderRef, Block: LLVMBasicBlockRef) --- + LLVMAppendExistingBasicBlock :: proc(Fn: LLVMValueRef, Block: LLVMBasicBlockRef) --- LLVMPrintModuleToFile :: proc(M: LLVMModuleRef, Filename: cstring, ErrorMessage: ^cstring) -> LLVMBool --- @@ -107,8 +125,16 @@ foreign llvmc { LLVMBuildAlloca :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildStore :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, Ptr: LLVMValueRef) -> LLVMValueRef --- LLVMBuildLoad2 :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, PointerVal: LLVMValueRef, Name: cstring) -> LLVMValueRef --- + LLVMBuildBr :: proc(Builder: LLVMBuilderRef, Dest: LLVMBasicBlockRef) -> LLVMValueRef --- + LLVMBuildCondBr :: proc(Builder: LLVMBuilderRef, If: LLVMValueRef, Then: LLVMBasicBlockRef, Else: LLVMBasicBlockRef) -> LLVMValueRef --- + LLVMBuildICmp :: proc(Builder: LLVMBuilderRef, Predicate: LLVMIntPredicate, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef --- + + LLVMBuildPhi :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- + LLVMTypeOf :: proc(Val: LLVMValueRef) -> LLVMTypeRef --- + LLVMAddIncoming :: proc(PhiNode: LLVMValueRef, IncomingValues: [^]LLVMValueRef, IncomingBlocks: [^]LLVMBasicBlockRef, Count: uint) --- + LLVMDisposeBuilder :: proc(Builder: LLVMBuilderRef) --- LLVMDisposeModule :: proc(M: LLVMModuleRef) --- LLVMContextDispose :: proc(C: LLVMContextRef) --- diff --git a/src/type_checker.odin b/src/type_checker.odin index ae05d70..fd6beb0 100644 --- a/src/type_checker.odin +++ b/src/type_checker.odin @@ -145,6 +145,10 @@ type_check_function_call :: proc(ast: ^Node, parent_ast: ^Node, must_be_function type_check :: proc(ast: ^Node, parent_ast: ^Node) { in_extern := false + if ast == nil { + return + } + #partial switch (ast.kind) { case .Integer: fallthrough case .Float: fallthrough @@ -301,6 +305,22 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) { ast.return_type = ast_to_type(ast.children[1]) } scope_stack[len(scope_stack) - 1].variable_definitions[get_character_sum_of_dyn_arr(&ast.children[0].value.([dynamic]u8))] = ast.return_type + case .If: + type_check(ast.children[0], ast) + if ast.children[0].return_type == nil || ast.children[0].return_type.kind != .Integer { + append(&g_message_list, + message_create( + .Error, + fmt.aprintf("If condition must be a signed/unsigned integer"), + ast.children[0].range, + ), + ) + break + } + type_check(ast.children[1], ast) + if len(ast.children) == 3 { + type_check(ast.children[2], ast) + } case .ExternFunction: in_extern = true fallthrough diff --git a/test_type_checker.cat b/test_type_checker.cat index ce23301..ea19a7c 100644 --- a/test_type_checker.cat +++ b/test_type_checker.cat @@ -14,3 +14,13 @@ fn put_i32(val: i32) i32 let amogus := 500 + (put_i32 8008135) put_i32 69 * amogus + 420 + +if 0 { + if 0 { + put_i32 123 + } else { + put_i32 69 + } +} else { + put_i32 456 +}