aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorgingerBill <ginger.bill.22@gmail.com>2016-07-31 23:01:42 +0100
committergingerBill <ginger.bill.22@gmail.com>2016-07-31 23:01:42 +0100
commit70f6282f41cdd7f500159116c520140364f6739a (patch)
tree577ba99ea8249236dc4a70695a1e94ef26ddb340 /src/codegen
parent776dc0e8f1aa506ae0096c78ff10565e56c175e7 (diff)
Variable declaration and assign, unary operators
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/print.cpp19
-rw-r--r--src/codegen/ssa.cpp284
2 files changed, 238 insertions, 65 deletions
diff --git a/src/codegen/print.cpp b/src/codegen/print.cpp
index 6ce039e0b..8e7f33ac9 100644
--- a/src/codegen/print.cpp
+++ b/src/codegen/print.cpp
@@ -146,7 +146,7 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
if (i > 0) ssa_fprintf(f, ", ");
ssa_print_type(f, s, &t->procedure.params[i]);
}
- ssa_fprintf(f, ")");
+ ssa_fprintf(f, ") ");
break;
}
}
@@ -159,7 +159,7 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
case ExactValue_String: {
ssa_fprintf(f, "{");
ssa_print_type(f, m->sizes, &basic_types[Basic_i8]);
- ssa_fprintf(f, "* \"");
+ ssa_fprintf(f, "* c\"");
// TODO(bill): Make unquote string function
String unquoted = value.value_string;
unquoted.text++;
@@ -209,7 +209,7 @@ void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint)
}
switch (value->kind) {
case ssaValue_TypeName:
- ssa_print_encoded_local(f, value->type_name->token.string);
+ ssa_print_encoded_local(f, value->type_name.entity->token.string);
break;
case ssaValue_Global:
ssa_print_encoded_global(f, value->global.entity->token.string);
@@ -237,7 +237,9 @@ void ssa_print_instruction(gbFile *f, ssaModule *m, ssaValue *value) {
Type *type = instr->local.entity->type;
ssa_fprintf(f, "%%%d = alloca ", value->id);
ssa_print_type(f, m->sizes, type);
- ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, gb_heap_allocator(), type));
+ ssa_fprintf(f, ", align %lld ", type_align_of(m->sizes, gb_heap_allocator(), type));
+ ssa_fprintf(f, "; %.*s", LIT(instr->local.entity->token.string));
+ ssa_fprintf(f, "\n");
ssa_fprintf(f, "\tstore ");
ssa_print_type(f, m->sizes, type);
ssa_fprintf(f, " zeroinitializer, ");
@@ -271,9 +273,11 @@ void ssa_print_instruction(gbFile *f, ssaModule *m, ssaValue *value) {
case ssaInstruction_BinaryOp: {
- ssaBinaryOp *bo = &value->instruction.binary_op;
+ auto *bo = &value->instruction.binary_op;
Type *type = ssa_value_type(bo->left);
+ ssa_fprintf(f, "%%%d = ", value->id);
+
if (is_type_float(type))
ssa_fprintf(f, "f");
@@ -320,15 +324,14 @@ void ssa_print_instruction(gbFile *f, ssaModule *m, ssaValue *value) {
}
void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
- gb_printf("-- Printing LLVM-IR -- \n\n");
gb_for_array(member_index, m->members.entries) {
auto *entry = &m->members.entries[member_index];
ssaValue *v = entry->value;
switch (v->kind) {
case ssaValue_TypeName: {
- ssa_print_encoded_local(f, v->type_name->token.string);
+ ssa_print_encoded_local(f, v->type_name.entity->token.string);
ssa_fprintf(f, " = type ");
- ssa_print_type(f, m->sizes, get_base_type(v->type_name->type));
+ ssa_print_type(f, m->sizes, get_base_type(v->type_name.type));
ssa_fprintf(f, "\n");
} break;
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;