Browse Source

Basic Comparisons

gingerBill 9 years ago
parent
commit
88e05ad2b2
7 changed files with 124 additions and 46 deletions
  1. 2 0
      examples/test.c
  2. 0 14
      examples/test.ll
  3. 1 4
      examples/test.odin
  4. 3 1
      run.bat
  5. 53 23
      src/codegen/print.cpp
  6. 64 3
      src/codegen/ssa.cpp
  7. 1 1
      src/tokenizer.cpp

+ 2 - 0
examples/test.c

@@ -1,4 +1,6 @@
 int main() {
 	float a = 0.5;
+	float b = 1.5;
+	int c = a < b;
 	return 0;
 }

+ 0 - 14
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
 }

+ 1 - 4
examples/test.odin

@@ -1,6 +1,3 @@
 main :: proc() {
-	a, b := 1, 2;
-	a++;
-	b++;
-	a += b;
+	a : int;
 }

+ 3 - 1
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

+ 53 - 23
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, " ");

+ 64 - 3
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:

+ 1 - 1
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"), \