diff --git a/examples/test.c b/examples/test.c index 6128d4e54..84a4f9a08 100644 --- a/examples/test.c +++ b/examples/test.c @@ -1,4 +1,6 @@ int main() { float a = 0.5; + float b = 1.5; + int c = a < b; return 0; } diff --git a/examples/test.ll b/examples/test.ll index ab38f5331..9835e90a7 100644 --- a/examples/test.ll +++ b/examples/test.ll @@ -2,19 +2,5 @@ define void @main() { entry: %0 = alloca i64, align 8 ; a store i64 zeroinitializer, i64* %0 - %1 = alloca i64, align 8 ; b - store i64 zeroinitializer, i64* %1 - store i64 1, i64* %0 - store i64 2, i64* %1 - %2 = load i64, i64* %0 - %3 = add i64 %2, 1 - store i64 %3, i64* %0 - %4 = load i64, i64* %1 - %5 = add i64 %4, 1 - store i64 %5, i64* %1 - %6 = load i64, i64* %1 - %7 = load i64, i64* %0 - %8 = add i64 %7, %6 - store i64 %8, i64* %0 ret void } diff --git a/examples/test.odin b/examples/test.odin index 8732d307e..962b48057 100644 --- a/examples/test.odin +++ b/examples/test.odin @@ -1,6 +1,3 @@ main :: proc() { - a, b := 1, 2; - a++; - b++; - a += b; + a : int; } diff --git a/run.bat b/run.bat index d2ce22d1c..418b2e059 100644 --- a/run.bat +++ b/run.bat @@ -4,4 +4,6 @@ rem del "..\examples\test.bc" call ..\bin\odin.exe ..\examples/test.odin call lli ..\examples/test.ll -rem call clang ..\examples/test.c -S -emit-llvm -o - +rem call opt -mem2reg ..\examples/test.ll > ..\examples/test.bc +rem call llvm-dis ..\examples/test.bc -o..\examples/test.ll +rem call clang ..\examples/test.c -O1 -S -emit-llvm -o ..\examples/test-c.ll diff --git a/src/codegen/print.cpp b/src/codegen/print.cpp index 8e7f33ac9..63b846c46 100644 --- a/src/codegen/print.cpp +++ b/src/codegen/print.cpp @@ -278,33 +278,63 @@ void ssa_print_instruction(gbFile *f, ssaModule *m, ssaValue *value) { ssa_fprintf(f, "%%%d = ", value->id); - if (is_type_float(type)) - ssa_fprintf(f, "f"); - - switch (bo->op.kind) { - case Token_Add: ssa_fprintf(f, "add"); break; - case Token_Sub: ssa_fprintf(f, "sub"); break; - case Token_And: ssa_fprintf(f, "and"); break; - case Token_Or: ssa_fprintf(f, "or"); break; - case Token_Xor: ssa_fprintf(f, "xor"); break; - - case Token_AndNot: GB_PANIC("TODO(bill): print Token_AndNot"); - - case Token_Mul: ssa_fprintf(f, "mul"); break; - - default: { - if (!is_type_float(type)) { - if (is_type_unsigned(type)) - ssa_fprintf(f, "u"); - else - ssa_fprintf(f, "s"); + if (gb_is_between(bo->op.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) { + if (is_type_float(type)) { + ssa_fprintf(f, "fcmp "); + switch (bo->op.kind) { + case Token_CmpEq: ssa_fprintf(f, "oeq"); break; + case Token_NotEq: ssa_fprintf(f, "one"); break; + case Token_Lt: ssa_fprintf(f, "olt"); break; + case Token_Gt: ssa_fprintf(f, "ogt"); break; + case Token_LtEq: ssa_fprintf(f, "ole"); break; + case Token_GtEq: ssa_fprintf(f, "oge"); break; + } + } else { + ssa_fprintf(f, "icmp "); + if (bo->op.kind != Token_CmpEq && + bo->op.kind != Token_NotEq) { + if (is_type_unsigned(type)) { + ssa_fprintf(f, "s"); + } else { + ssa_fprintf(f, "u"); + } + } + switch (bo->op.kind) { + case Token_CmpEq: ssa_fprintf(f, "eq"); break; + case Token_NotEq: ssa_fprintf(f, "ne"); break; + case Token_Lt: ssa_fprintf(f, "lt"); break; + case Token_Gt: ssa_fprintf(f, "gt"); break; + case Token_LtEq: ssa_fprintf(f, "le"); break; + case Token_GtEq: ssa_fprintf(f, "ge"); break; + } } + } else { + if (is_type_float(type)) + ssa_fprintf(f, "f"); switch (bo->op.kind) { - case Token_Quo: ssa_fprintf(f, "div"); break; - case Token_Mod: ssa_fprintf(f, "rem"); break; + case Token_Add: ssa_fprintf(f, "add"); break; + case Token_Sub: ssa_fprintf(f, "sub"); break; + case Token_And: ssa_fprintf(f, "and"); break; + case Token_Or: ssa_fprintf(f, "or"); break; + case Token_Xor: ssa_fprintf(f, "xor"); break; + + case Token_AndNot: GB_PANIC("Token_AndNot Should never be called"); + + case Token_Mul: ssa_fprintf(f, "mul"); break; + + default: { + if (!is_type_float(type)) { + if (is_type_unsigned(type)) ssa_fprintf(f, "u"); + else ssa_fprintf(f, "s"); + } + + switch (bo->op.kind) { + case Token_Quo: ssa_fprintf(f, "div"); break; + case Token_Mod: ssa_fprintf(f, "rem"); break; + } + } break; } - } break; } ssa_fprintf(f, " "); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 070c3a1d6..b7d925d07 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -104,6 +104,7 @@ struct ssaInstruction { struct { + Type *type; Token op; ssaValue *left, *right; } binary_op; @@ -114,10 +115,10 @@ struct ssaInstruction { enum ssaValueKind { ssaValue_Invalid, + ssaValue_Constant, ssaValue_TypeName, ssaValue_Global, ssaValue_Procedure, - ssaValue_Constant, ssaValue_Block, ssaValue_Instruction, @@ -130,10 +131,10 @@ struct ssaValue { i32 id; union { + ssaConstant constant; ssaTypeName type_name; ssaGlobal global; ssaProcedure procedure; - ssaConstant constant; ssaBlock block; ssaInstruction instruction; }; @@ -157,6 +158,7 @@ struct ssaLvalue { }; }; + void ssa_module_init(ssaModule *m, Checker *c) { m->allocator = gb_heap_allocator(); m->info = &c->info; @@ -187,6 +189,8 @@ Type *ssa_instruction_type(ssaInstruction *instr) { return ssa_value_type(instr->store.address); case ssaInstruction_Load: return ssa_value_type(instr->load.address); + case ssaInstruction_BinaryOp: + return instr->binary_op.type; } return NULL; } @@ -202,6 +206,9 @@ void ssa_instruction_set_type(ssaInstruction *instr, Type *type) { case ssaInstruction_Load: // NOTE(bill): Do nothing break; + case ssaInstruction_BinaryOp: + instr->binary_op.type = type; + break; } } @@ -558,6 +565,31 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue return ssa_emit(proc, v); } +ssaValue *ssa_emit_compare(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) { + Type *a = get_base_type(ssa_value_type(left)); + Type *b = get_base_type(ssa_value_type(right)); + + if (op.kind == Token_CmpEq && + left->kind == ssaValue_Constant && left->constant.value.kind == ExactValue_Bool) { + if (left->constant.value.value_bool) { + if (is_type_boolean(b)) + return right; + } + } + + if (are_types_identical(a, b)) { + // NOTE(bill): No need for a conversion + } else if (left->kind == ssaValue_Constant) { + left = ssa_emit_conversion(proc, left, ssa_value_type(right)); + } else if (right->kind == ssaValue_Constant) { + right = ssa_emit_conversion(proc, right, ssa_value_type(left)); + } + + ssaValue *v = ssa_make_instruction_binary_op(proc, op, left, right); + ssa_value_set_type(v, &basic_types[Basic_bool]); + return ssa_emit(proc, v); +} + ssaValue *ssa_build_single_expression(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) { switch (expr->kind) { case AstNode_Identifier: { @@ -573,6 +605,9 @@ ssaValue *ssa_build_single_expression(ssaProcedure *proc, AstNode *expr, TypeAnd } } break; + case AstNode_ParenExpression: + return ssa_build_single_expression(proc, unparen_expression(expr), tv); + case AstNode_DereferenceExpression: { ssaLvalue addr = ssa_build_address(proc, expr->dereference_expression.operand); return ssa_lvalue_load(addr, proc); @@ -617,11 +652,37 @@ ssaValue *ssa_build_single_expression(ssaProcedure *proc, AstNode *expr, TypeAnd case Token_And: case Token_Or: case Token_Xor: - case Token_AndNot: return ssa_emit_arith(proc, be->op, ssa_build_expression(proc, be->left), ssa_build_expression(proc, be->right), tv->type); + + case Token_AndNot: { + AstNode ue = {AstNode_UnaryExpression}; + ue.unary_expression.op = be->op; + ue.unary_expression.op.kind = Token_Xor; + ue.unary_expression.operand = be->right; + ssaValue *left = ssa_build_expression(proc, be->left); + ssaValue *right = ssa_build_expression(proc, &ue); + Token op = be->op; + op.kind = Token_And; + return ssa_emit_arith(proc, op, left, right, tv->type); + } break; + + case Token_CmpEq: + case Token_NotEq: + case Token_Lt: + case Token_LtEq: + case Token_Gt: + case Token_GtEq: { + ssaValue *cmp = ssa_emit_compare(proc, be->op, + ssa_build_expression(proc, be->left), + ssa_build_expression(proc, be->right)); + return ssa_emit_conversion(proc, cmp, default_type(tv->type)); + } break; + + default: + GB_PANIC("Invalid binary expression"); } } break; case AstNode_ProcedureLiteral: diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 8d1a7e4af..c03c9ce7a 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -74,9 +74,9 @@ TOKEN_KIND(_AssignOpEnd, "_AssignOpEnd"), \ \ TOKEN_KIND(_ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(CmpEq, "=="), \ + TOKEN_KIND(NotEq, "!="), \ TOKEN_KIND(Lt, "<"), \ TOKEN_KIND(Gt, ">"), \ - TOKEN_KIND(NotEq, "!="), \ TOKEN_KIND(LtEq, "<="), \ TOKEN_KIND(GtEq, ">="), \ TOKEN_KIND(_ComparisonEnd, "_ComparisonEnd"), \