mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Fix and improve x->y() behaviour to minimize duplicate evaluation
This commit is contained in:
@@ -294,6 +294,7 @@ struct lbProcedure {
|
|||||||
lbCopyElisionHint copy_elision_hint;
|
lbCopyElisionHint copy_elision_hint;
|
||||||
|
|
||||||
PtrMap<Ast *, lbValue> selector_values;
|
PtrMap<Ast *, lbValue> selector_values;
|
||||||
|
PtrMap<Ast *, lbAddr> selector_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3039,6 +3039,12 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
|||||||
map_remove(&p->selector_values, expr);
|
map_remove(&p->selector_values, expr);
|
||||||
return res;
|
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);
|
lbValue res = lb_build_expr_internal(p, expr);
|
||||||
if (expr->state_flags & StateFlag_SelectorCallExpr) {
|
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) {
|
lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||||
expr = unparen_expr(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) {
|
switch (expr->kind) {
|
||||||
case_ast_node(i, Implicit, expr);
|
case_ast_node(i, Implicit, expr);
|
||||||
lbAddr v = {};
|
lbAddr v = {};
|
||||||
@@ -3574,9 +3605,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(se, SelectorCallExpr, expr);
|
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);
|
lbValue e = lb_build_expr(p, expr);
|
||||||
return lb_addr(lb_address_from_load_or_generate_local(p, e));
|
return lb_addr(lb_address_from_load_or_generate_local(p, e));
|
||||||
case_end;
|
case_end;
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
|||||||
p->branch_blocks.allocator = a;
|
p->branch_blocks.allocator = a;
|
||||||
p->context_stack.allocator = a;
|
p->context_stack.allocator = a;
|
||||||
p->scope_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) {
|
if (p->is_foreign) {
|
||||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
||||||
|
|||||||
Reference in New Issue
Block a user