diff options
Diffstat (limited to 'src/codegen/ssa.cpp')
| -rw-r--r-- | src/codegen/ssa.cpp | 284 |
1 files changed, 227 insertions, 57 deletions
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index d17264f64..070c3a1d6 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -30,41 +30,35 @@ struct ssaProcedure { ssaModule *module; String name; Entity *entity; + Type *type; DeclarationInfo *decl; AstNode *type_expr; AstNode *body; gbArray(ssaValue *) blocks; ssaBlock *curr_block; + gbArray(ssaValue *) anonymous_procedures; }; -struct ssaLocal { + +struct ssaTypeName { Entity *entity; + Type *type; }; struct ssaGlobal { b32 generated; Entity *entity; + Type *type; ssaValue *value; }; -struct ssaStore { - ssaValue *address; - ssaValue *value; -}; -struct ssaLoad { - ssaValue *address; -}; -struct ssaBinaryOp { - Token op; - ssaValue *left, *right; -}; -struct ssaGetElementPtr { - ssaValue *address; - Type *result_type; - Type *element_type; - gbArray(ssaValue *) indices; +struct ssaConstant { + Type *type; + ExactValue value; }; + + enum ssaInstructionKind { ssaInstruction_Invalid, @@ -73,6 +67,8 @@ enum ssaInstructionKind { ssaInstruction_Load, ssaInstruction_GetElementPtr, + ssaInstruction_Convert, + ssaInstruction_BinaryOp, ssaInstruction_Count, @@ -86,12 +82,31 @@ struct ssaInstruction { TokenPos pos; union { - ssaLocal local; - ssaStore store; - ssaLoad load; - ssaGetElementPtr get_element_ptr; + struct { + Entity *entity; + Type *type; + } local; + struct { + ssaValue *address; + ssaValue *value; + } store; + struct { + ssaValue *address; + } load; + struct { + ssaValue *address; + Type *result_type; + Type *element_type; + isize index_count; + isize indices[2]; + } get_element_ptr; - ssaBinaryOp binary_op; + + + struct { + Token op; + ssaValue *left, *right; + } binary_op; }; }; @@ -115,10 +130,10 @@ struct ssaValue { i32 id; union { - Entity * type_name; + ssaTypeName type_name; ssaGlobal global; ssaProcedure procedure; - TypeAndValue constant; + ssaConstant constant; ssaBlock block; ssaInstruction instruction; }; @@ -162,11 +177,12 @@ void ssa_module_add_value(ssaModule *m, Entity *e, ssaValue *v) { Type *ssa_value_type(ssaValue *value); +void ssa_value_set_type(ssaValue *value, Type *type); Type *ssa_instruction_type(ssaInstruction *instr) { switch (instr->kind) { case ssaInstruction_Local: - return instr->local.entity->type; + return instr->local.type; case ssaInstruction_Store: return ssa_value_type(instr->store.address); case ssaInstruction_Load: @@ -175,14 +191,28 @@ Type *ssa_instruction_type(ssaInstruction *instr) { return NULL; } +void ssa_instruction_set_type(ssaInstruction *instr, Type *type) { + switch (instr->kind) { + case ssaInstruction_Local: + instr->local.type = type; + break; + case ssaInstruction_Store: + ssa_value_set_type(instr->store.value, type); + break; + case ssaInstruction_Load: + // NOTE(bill): Do nothing + break; + } +} + Type *ssa_value_type(ssaValue *value) { switch (value->kind) { case ssaValue_TypeName: - return value->type_name->type; + return value->type_name.type; case ssaValue_Global: - return value->global.entity->type; + return value->global.type; case ssaValue_Procedure: - return value->procedure.entity->type; + return value->procedure.type; case ssaValue_Constant: return value->constant.type; case ssaValue_Instruction: @@ -192,9 +222,32 @@ Type *ssa_value_type(ssaValue *value) { } +void ssa_value_set_type(ssaValue *value, Type *type) { + switch (value->kind) { + case ssaValue_TypeName: + value->type_name.type = type; + break; + case ssaValue_Global: + value->global.type = type; + break; + case ssaValue_Procedure: + value->procedure.type = type; + break; + case ssaValue_Constant: + value->constant.type = type; + break; + case ssaValue_Instruction: + ssa_instruction_set_type(&value->instruction, type); + break; + } +} +ssaValue *ssa_build_expression(ssaProcedure *proc, AstNode *expr); +ssaValue *ssa_build_single_expression(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv); +ssaLvalue ssa_build_address(ssaProcedure *proc, AstNode *expr); +ssaValue *ssa_emit_conversion(ssaProcedure *proc, ssaValue *value, Type *a_type); @@ -215,14 +268,16 @@ ssaValue *ssa_alloc_instruction(gbAllocator a, ssaInstructionKind kind) { ssaValue *ssa_make_value_type_name(gbAllocator a, Entity *e) { ssaValue *v = ssa_alloc_value(a, ssaValue_TypeName); - v->type_name = e; + v->type_name.entity = e; + v->type_name.type = e->type; return v; } ssaValue *ssa_make_value_global(gbAllocator a, Entity *e, ssaValue *value) { ssaValue *v = ssa_alloc_value(a, ssaValue_Global); v->global.entity = e; - v->global.value = value; + v->global.type = e->type; + v->global.value = value; return v; } @@ -232,6 +287,7 @@ ssaValue *ssa_make_instruction_local(ssaProcedure *p, Entity *e) { ssaValue *v = ssa_alloc_instruction(p->module->allocator, ssaInstruction_Local); ssaInstruction *i = &v->instruction; i->local.entity = e; + i->local.type = e->type; if (p->curr_block) { gb_array_append(p->curr_block->values, v); } @@ -295,6 +351,7 @@ ssaValue *ssa_make_value_procedure(gbAllocator a, Entity *e, DeclarationInfo *de ssaValue *v = ssa_alloc_value(a, ssaValue_Procedure); v->procedure.module = m; v->procedure.entity = e; + v->procedure.type = e->type; v->procedure.decl = decl; v->procedure.name = e->token.string; return v; @@ -302,9 +359,9 @@ ssaValue *ssa_make_value_procedure(gbAllocator a, Entity *e, DeclarationInfo *de ssaValue *ssa_make_value_block(gbAllocator a, ssaProcedure *proc, AstNode *node, Scope *scope, String label) { ssaValue *v = ssa_alloc_value(a, ssaValue_Block); - v->block.label = label; - v->block.node = node; - v->block.scope = scope; + v->block.label = label; + v->block.node = node; + v->block.scope = scope; v->block.parent = proc; gb_array_init(v->block.instructions, gb_heap_allocator()); @@ -421,6 +478,8 @@ ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value) { ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address) { ssaValue *v = ssa_make_instruction_load(p, address); + Type *t = ssa_value_type(address); + ssa_value_set_type(v, type_deref(t)); ssa_emit(p, v); return v; } @@ -452,22 +511,28 @@ ssaValue *ssa_lvalue_address(ssaLvalue lval, ssaProcedure *p) { return NULL; } -ssaValue *ssa_build_expression(ssaProcedure *proc, AstNode *expr); -ssaValue *ssa_build_single_expression(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv); +Type *ssa_lvalue_type(ssaLvalue lval) { + switch (lval.kind) { + case ssaLvalue_Address: + return type_deref(ssa_value_type(lval.address.value)); + } + return NULL; +} -ssaValue *ssa_emit_conversion(ssaProcedure *proc, ssaValue *value, Type *a_type) { - Type *b_type = ssa_value_type(value); - if (are_types_identical(a_type, b_type)) +ssaValue *ssa_emit_conversion(ssaProcedure *proc, ssaValue *value, Type *t) { + Type *src_type = ssa_value_type(value); + if (are_types_identical(t, src_type)) return value; - Type *a = get_base_type(a_type); - Type *b = get_base_type(b_type); + Type *dst = get_base_type(t); + Type *src = get_base_type(src_type); if (value->kind == ssaValue_Constant) { - if (a->kind == Type_Basic) - return ssa_make_value_constant(proc->module->allocator, a_type, value->constant.value); + if (dst->kind == Type_Basic) + return ssa_make_value_constant(proc->module->allocator, t, value->constant.value); } + GB_PANIC("TODO(bill): ssa_emit_conversion"); return NULL; @@ -508,19 +573,36 @@ ssaValue *ssa_build_single_expression(ssaProcedure *proc, AstNode *expr, TypeAnd } } break; + case AstNode_DereferenceExpression: { + ssaLvalue addr = ssa_build_address(proc, expr->dereference_expression.operand); + return ssa_lvalue_load(addr, proc); + } break; + case AstNode_UnaryExpression: { auto *ue = &expr->unary_expression; switch (ue->op.kind) { + case Token_Pointer: + return ssa_lvalue_address(ssa_build_address(proc, ue->operand), proc); case Token_Add: return ssa_build_expression(proc, ue->operand); - case Token_Sub: - return NULL; - case Token_Xor: - return NULL; - case Token_Not: - return NULL; - case Token_Pointer: + case Token_Sub: { + // NOTE(bill): -x == 0 - x + ExactValue zero = make_exact_value_integer(0); + ssaValue *left = ssa_make_value_constant(proc->module->allocator, tv->type, zero); + ssaValue *right = ssa_build_expression(proc, ue->operand); + return ssa_emit_arith(proc, ue->op, left, right, tv->type); + } break; + case Token_Xor: { // Bitwise not + // NOTE(bill): "not" x == x "xor" -1 + ExactValue neg_one = make_exact_value_integer(-1); + ssaValue *left = ssa_build_expression(proc, ue->operand); + ssaValue *right = ssa_make_value_constant(proc->module->allocator, tv->type, neg_one); + return ssa_emit_arith(proc, ue->op, left, right, tv->type); + } break; + case Token_Not: // Boolean not + GB_PANIC("Token_Not"); return NULL; + } } break; @@ -550,8 +632,9 @@ ssaValue *ssa_build_single_expression(ssaProcedure *proc, AstNode *expr, TypeAnd break; case AstNode_SliceExpression: break; - case AstNode_IndexExpression: - break; + case AstNode_IndexExpression: { + + } break; case AstNode_SelectorExpression: break; } @@ -609,7 +692,8 @@ ssaLvalue ssa_build_address(ssaProcedure *proc, AstNode *expr) { case AstNode_DereferenceExpression: { ssaLvalue val = {ssaLvalue_Address}; - val.address.value = ssa_build_expression(proc, expr); + AstNode *operand = expr->dereference_expression.operand; + val.address.value = ssa_build_expression(proc, operand); val.address.expr = expr; return val; } break; @@ -623,10 +707,20 @@ ssaLvalue ssa_build_address(ssaProcedure *proc, AstNode *expr) { // TODO(bill): Others address } + GB_PANIC("Unexpected address expression"); + ssaLvalue blank = {ssaLvalue_Blank}; return blank; } +void ssa_build_assign_op(ssaProcedure *proc, ssaLvalue lhs, ssaValue *value, Token op) { + ssaValue *old_value = ssa_lvalue_load(lhs, proc); + ssaValue *change = ssa_emit_conversion(proc, value, ssa_value_type(old_value)); + ssaValue *new_value = ssa_emit_arith(proc, op, old_value, change, ssa_lvalue_type(lhs)); + ssa_lvalue_store(lhs, proc, new_value); +} + + void ssa_build_statement(ssaProcedure *proc, AstNode *s); void ssa_build_statement_list(ssaProcedure *proc, AstNode *list) { @@ -642,6 +736,32 @@ void ssa_build_statement(ssaProcedure *proc, AstNode *s) { auto *vd = &s->variable_declaration; if (vd->kind == Declaration_Mutable) { if (vd->name_count == vd->value_count) { // 1:1 assigment + gbArray(ssaLvalue) lvals; + gbArray(ssaValue *) inits; + gb_array_init_reserve(lvals, gb_heap_allocator(), vd->name_count); + gb_array_init_reserve(inits, gb_heap_allocator(), vd->name_count); + defer (gb_array_free(lvals)); + defer (gb_array_free(inits)); + + for (AstNode *name = vd->name_list; name != NULL; name = name->next) { + ssaLvalue lval = {ssaLvalue_Blank}; + if (!ssa_is_blank_identifier(name)) { + ssa_add_local_for_identifier(proc, name); + lval = ssa_build_address(proc, name); + } + + gb_array_append(lvals, lval); + } + + for (AstNode *value = vd->value_list; value != NULL; value = value->next) { + ssaValue *init = ssa_build_expression(proc, value); + gb_array_append(inits, init); + } + + + gb_for_array(i, inits) { + ssa_lvalue_store(lvals[i], proc, inits[i]); + } } else if (vd->value_count == 0) { // declared and zero-initialized for (AstNode *name = vd->name_list; name != NULL; name = name->next) { @@ -656,6 +776,20 @@ void ssa_build_statement(ssaProcedure *proc, AstNode *s) { } } break; + case AstNode_IncDecStatement: { + Token op = s->inc_dec_statement.op; + if (op.kind == Token_Increment) { + op.kind = Token_Add; + } else if (op.kind == Token_Decrement) { + op.kind = Token_Sub; + } + ssaLvalue lval = ssa_build_address(proc, s->inc_dec_statement.expression); + ssaValue *one = ssa_make_value_constant(proc->module->allocator, ssa_lvalue_type(lval), + make_exact_value_integer(1)); + ssa_build_assign_op(proc, lval, one, op); + + } break; + case AstNode_AssignStatement: { auto *assign = &s->assign_statement; switch (assign->op.kind) { @@ -681,16 +815,36 @@ void ssa_build_statement(ssaProcedure *proc, AstNode *s) { ssaValue *init = ssa_build_expression(proc, rhs); ssa_lvalue_store(lvals[0], proc, init); } else { - GB_PANIC("TODO(bill): parallel assignment"); + gbArray(ssaValue *) inits; + gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(lvals)); + defer (gb_array_free(inits)); + + for (AstNode *rhs = assign->rhs_list; rhs != NULL; rhs = rhs->next) { + ssaValue *init = ssa_build_expression(proc, rhs); + gb_array_append(inits, init); + } + + gb_for_array(i, inits) { + ssa_lvalue_store(lvals[i], proc, inits[i]); + } } } else { - GB_PANIC("TODO(bill): tuple assignment"); + GB_PANIC("TODO(bill): tuple assignment"); } } break; - default: // +=, -=, etc - break; + default: { + // NOTE(bill): Only 1 += 1 is allowed, no tuples + // +=, -=, etc + Token op = assign->op; + i32 kind = op.kind; + kind += Token_Add - Token_AddEq; // Convert += to + + op.kind = cast(TokenKind)kind; + ssaLvalue lhs = ssa_build_address(proc, assign->lhs_list); + ssaValue *value = ssa_build_expression(proc, assign->rhs_list); + ssa_build_assign_op(proc, lhs, value, op); + } break; } } break; @@ -701,6 +855,22 @@ void ssa_build_statement(ssaProcedure *proc, AstNode *s) { case AstNode_BlockStatement: ssa_build_statement_list(proc, s->block_statement.list); break; + + case AstNode_IfStatement: + GB_PANIC("AstNode_IfStatement"); + break; + case AstNode_ReturnStatement: + GB_PANIC("AstNode_ReturnStatement"); + break; + case AstNode_ForStatement: + GB_PANIC("AstNode_ForStatement"); + break; + case AstNode_DeferStatement: + GB_PANIC("AstNode_DeferStatement"); + break; + case AstNode_BranchStatement: + GB_PANIC("AstNode_BranchStatement"); + break; } } @@ -709,7 +879,7 @@ void ssa_build_statement(ssaProcedure *proc, AstNode *s) { void ssa_build_procedure(ssaValue *value) { ssaProcedure *proc = &value->procedure; - gb_printf("Building %.*s: %.*s\n", LIT(entity_strings[proc->entity->kind]), LIT(proc->name)); + // gb_printf("Building %.*s: %.*s\n", LIT(entity_strings[proc->entity->kind]), LIT(proc->name)); AstNode *proc_decl = proc->decl->proc_decl; |