aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/ssa.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/ssa.cpp')
-rw-r--r--src/codegen/ssa.cpp60
1 files changed, 36 insertions, 24 deletions
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp
index c346f39b3..6c5b8f51b 100644
--- a/src/codegen/ssa.cpp
+++ b/src/codegen/ssa.cpp
@@ -1606,7 +1606,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
if (elem->kind == AstNode_FieldValue) {
ast_node(kv, FieldValue, elem);
- Entity *e = lookup_field(base_type, kv->field, &field_index);
+ Selection sel = lookup_field(base_type, kv->field->Ident.token.string);
+ field_index = sel.index[0];
field_expr = ssa_build_expr(proc, kv->value);
} else {
field_expr = ssa_build_expr(proc, elem);
@@ -1874,6 +1875,36 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) {
return value;
}
+ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, Selection sel) {
+ GB_ASSERT(gb_array_count(sel.index) > 0);
+
+ gb_for_array(i, sel.index) {
+ isize index = sel.index[i];
+ if (is_type_pointer(type)) {
+ type = type_deref(type);
+ e = ssa_emit_load(proc, e);
+ e = ssa_emit_ptr_offset(proc, e, v_zero);
+ ssa_set_type(e, type);
+ }
+ type = get_base_type(type);
+
+
+ if (type->kind == Type_Union) {
+ ssaValue *v = ssa_emit_ptr_offset(proc, e, v_zero);
+ ssa_set_type(v, make_type_pointer(proc->module->allocator, type));
+ type = type->Union.fields[index]->type;
+ e = ssa_emit_conv(proc, v, make_type_pointer(proc->module->allocator, type));
+ e = ssa_emit_ptr_offset(proc, e, v_zero);
+ ssa_set_type(e, type);
+ } else {
+ type = type->Union.fields[index]->type;
+ e = ssa_emit_struct_gep(proc, e, index, type);
+ }
+ }
+
+ return e;
+}
+
ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
switch (expr->kind) {
@@ -1901,31 +1932,12 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
case_ast_node(se, SelectorExpr, expr);
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
- isize field_index = 0;
- Entity *entity = lookup_field(type, unparen_expr(se->selector), &field_index);
- GB_ASSERT(entity != NULL);
+ Selection sel = lookup_field(type, unparen_expr(se->selector)->Ident.token.string);
+ GB_ASSERT(sel.entity != NULL);
ssaValue *e = ssa_build_addr(proc, se->expr).addr;
-
- if (is_type_pointer(type)) {
- // NOTE(bill): Allow x^.y and x.y to be the same
- e = ssa_emit_load(proc, e);
- e = ssa_emit_ptr_offset(proc, e, v_zero);
- ssa_set_type(e, type_deref(type));
- }
-
- if (type->kind == Type_Union) {
- ssaValue *v = ssa_emit_ptr_offset(proc, e, v_zero);
- ssa_set_type(v, make_type_pointer(proc->module->allocator, type));
- ssaValue *f = ssa_emit_conv(proc, v, make_type_pointer(proc->module->allocator, entity->type));
- f = ssa_emit_ptr_offset(proc, f, v_zero);
- ssa_set_type(f, entity->type);
- return ssa_make_addr(f, expr);
-
- } else {
- ssaValue *v = ssa_emit_struct_gep(proc, e, field_index, entity->type);
- return ssa_make_addr(v, expr);
- }
+ e = ssa_emit_deep_field_gep(proc, type, e, sel);
+ return ssa_make_addr(e, expr);
case_end;
case_ast_node(ue, UnaryExpr, expr);