diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 87a354a49..745dbbbc7 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -294,6 +294,7 @@ struct lbProcedure { lbCopyElisionHint copy_elision_hint; PtrMap selector_values; + PtrMap selector_addr; }; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 624d06188..1365028fc 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3039,6 +3039,12 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { map_remove(&p->selector_values, expr); return res; } + lbAddr *pa = map_get(&p->selector_addr, expr); + if (pa != nullptr) { + lbAddr res = *pa; + map_remove(&p->selector_addr, expr); + return lb_addr_load(p, res); + } } lbValue res = lb_build_expr_internal(p, expr); if (expr->state_flags & StateFlag_SelectorCallExpr) { @@ -3430,9 +3436,34 @@ lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue } +lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr); lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { expr = unparen_expr(expr); + // IMPORTANT NOTE(bill): + // Selector Call Expressions (foo->bar(...)) + // must only evaluate `foo` once as it gets transformed into + // `foo.bar(foo, ...)` + // And if `foo` is a procedure call or something more complex, storing the value + // once is a very good idea + // If a stored value is found, it must be removed from the cache + if (expr->state_flags & StateFlag_SelectorCallExpr) { + lbAddr *pp = map_get(&p->selector_addr, expr); + if (pp != nullptr) { + lbAddr res = *pp; + map_remove(&p->selector_addr, expr); + return res; + } + } + lbAddr addr = lb_build_addr_internal(p, expr); + if (expr->state_flags & StateFlag_SelectorCallExpr) { + map_set(&p->selector_addr, expr, addr); + } + return addr; +} + + +lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { switch (expr->kind) { case_ast_node(i, Implicit, expr); lbAddr v = {}; @@ -3574,9 +3605,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(se, SelectorCallExpr, expr); - GB_ASSERT(se->modified_call); - TypeAndValue tav = type_and_value_of_expr(expr); - GB_ASSERT(tav.mode != Addressing_Invalid); lbValue e = lb_build_expr(p, expr); return lb_addr(lb_address_from_load_or_generate_local(p, e)); case_end; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 0ffe1c4c7..0b0c0794b 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -113,7 +113,8 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) p->branch_blocks.allocator = a; p->context_stack.allocator = a; p->scope_stack.allocator = a; - map_init(&p->selector_values, a); + map_init(&p->selector_values, a, 0); + map_init(&p->selector_addr, a, 0); if (p->is_foreign) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);