aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2015-12-15 19:17:39 -0700
committerAndrew Kelley <superjoe30@gmail.com>2015-12-15 19:17:39 -0700
commit5a8822c714e4ee2d442e76f36213d119530f0fea (patch)
tree45c71c52e8f7304efc2f32cda40b3983d8b76e5e /src/codegen.cpp
parent28c5a8f2cab193858717594fc91df3369980e18c (diff)
downloadzig-5a8822c714e4ee2d442e76f36213d119530f0fea.tar.gz
zig-5a8822c714e4ee2d442e76f36213d119530f0fea.zip
fix assignment operators for struct fields
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp85
1 files changed, 56 insertions, 29 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 407eb0a7c4..0cc803d63c 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -206,7 +206,7 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
}
-static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
+static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
assert(node->type == NodeTypeFieldAccessExpr);
LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
@@ -217,6 +217,8 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
assert(codegen_field_access->field_index >= 0);
+ *out_type_entry = codegen_field_access->type_struct_field->type_entry;
+
add_debug_source_node(g, node);
return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");
}
@@ -243,34 +245,78 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
zig_panic("gen_field_access_expr bad array field");
}
} else if (struct_type->id == TypeTableEntryIdStruct) {
- LLVMValueRef ptr = gen_field_ptr(g, node);
+ TypeTableEntry *type_entry;
+ LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);
return LLVMBuildLoad(g->builder, ptr, "");
} else {
zig_panic("gen_field_access_expr bad struct type");
}
}
+static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *parent_node, AstNode *node,
+ TypeTableEntry **out_type_entry)
+{
+ LLVMValueRef target_ref;
+
+ if (node->type == NodeTypeSymbol) {
+ VariableTableEntry *var = find_variable(parent_node->codegen_node->expr_node.block_context,
+ &node->data.symbol);
+
+ // semantic checking ensures no variables are constant
+ assert(!var->is_const);
+
+ *out_type_entry = var->type;
+ target_ref = var->value_ref;
+ } else if (node->type == NodeTypeArrayAccessExpr) {
+ TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);
+ assert(array_type->id == TypeTableEntryIdArray);
+ *out_type_entry = array_type->data.array.child_type;
+ target_ref = gen_array_ptr(g, node);
+ } else if (node->type == NodeTypeFieldAccessExpr) {
+ target_ref = gen_field_ptr(g, node, out_type_entry);
+ } else {
+ zig_panic("bad assign target");
+ }
+
+ return target_ref;
+}
+
static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypePrefixOpExpr);
assert(node->data.prefix_op_expr.primary_expr);
- LLVMValueRef expr = gen_expr(g, node->data.prefix_op_expr.primary_expr);
+ AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
switch (node->data.prefix_op_expr.prefix_op) {
+ case PrefixOpInvalid:
+ zig_unreachable();
case PrefixOpNegation:
- add_debug_source_node(g, node);
- return LLVMBuildNeg(g->builder, expr, "");
+ {
+ LLVMValueRef expr = gen_expr(g, expr_node);
+ add_debug_source_node(g, node);
+ return LLVMBuildNeg(g->builder, expr, "");
+ }
case PrefixOpBoolNot:
{
+ LLVMValueRef expr = gen_expr(g, expr_node);
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr));
add_debug_source_node(g, node);
return LLVMBuildICmp(g->builder, LLVMIntEQ, expr, zero, "");
}
case PrefixOpBinNot:
- add_debug_source_node(g, node);
- return LLVMBuildNot(g->builder, expr, "");
- case PrefixOpInvalid:
- zig_unreachable();
+ {
+ LLVMValueRef expr = gen_expr(g, expr_node);
+ add_debug_source_node(g, node);
+ return LLVMBuildNot(g->builder, expr, "");
+ }
+ case PrefixOpAddressOf:
+ case PrefixOpConstAddressOf:
+ {
+ add_debug_source_node(g, node);
+ TypeTableEntry *lvalue_type;
+ return gen_lvalue(g, node, expr_node, &lvalue_type);
+ }
+
}
zig_unreachable();
}
@@ -571,33 +617,14 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
return phi;
}
-
static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
AstNode *lhs_node = node->data.bin_op_expr.op1;
- LLVMValueRef target_ref;
TypeTableEntry *op1_type;
- if (lhs_node->type == NodeTypeSymbol) {
- VariableTableEntry *var = find_variable(node->codegen_node->expr_node.block_context,
- &lhs_node->data.symbol);
-
- // semantic checking ensures no variables are constant
- assert(!var->is_const);
+ LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);
- op1_type = var->type;
- target_ref = var->value_ref;
- } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
- TypeTableEntry *array_type = get_expr_type(lhs_node->data.array_access_expr.array_ref_expr);
- assert(array_type->id == TypeTableEntryIdArray);
- op1_type = array_type->data.array.child_type;
- target_ref = gen_array_ptr(g, lhs_node);
- } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
- target_ref = gen_field_ptr(g, lhs_node);
- } else {
- zig_panic("bad assign target");
- }
LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
if (node->data.bin_op_expr.bin_op == BinOpTypeAssign) {