aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-05-24 20:57:44 +0100
committergingerBill <bill@gingerbill.org>2021-05-24 20:57:44 +0100
commitd35a9e65b68e9d38f470c3cf0e54909e08d7bde8 (patch)
treefff72bc37188bfe7174fa27b671234b1330aee74 /src/llvm_backend.cpp
parentc440296ae8b0f171fc0f7df311831954c9992162 (diff)
Heavily improve the copy elision logic in the backend
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp140
1 files changed, 96 insertions, 44 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index a0294aee0..bc519f70d 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -4927,6 +4927,23 @@ lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast
return res;
}
+lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast) {
+ lbCopyElisionHint prev = p->copy_elision_hint;
+ p->copy_elision_hint.used = false;
+ p->copy_elision_hint.ptr = {};
+ p->copy_elision_hint.ast = nullptr;
+ if (addr.kind == lbAddr_Default && addr.addr.value != nullptr) {
+ p->copy_elision_hint.ptr = lb_addr_get_ptr(p, addr);
+ p->copy_elision_hint.ast = unparen_expr(ast);
+ }
+ return prev;
+}
+
+void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint) {
+ p->copy_elision_hint = prev_hint;
+}
+
+
void lb_build_stmt(lbProcedure *p, Ast *node) {
Ast *prev_stmt = p->curr_stmt;
defer (p->curr_stmt = prev_stmt);
@@ -5084,6 +5101,47 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
lb_add_local(p, e->type, e, true);
}
}
+ } else if (vd->names.count == vd->values.count) {
+ auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
+ auto inits = array_make<lbValue>(permanent_allocator(), 0, vd->names.count);
+
+ for_array(i, vd->names) {
+ Ast *name = vd->names[i];
+ lbAddr lval = {};
+ if (!is_blank_ident(name)) {
+ Entity *e = entity_of_node(name);
+ bool zero_init = true;
+ if (vd->names.count == vd->values.count) {
+ // Possibly uses copy elision
+ // Make the caller mem zero
+ zero_init = true;
+ }
+ lval = lb_add_local(p, e->type, e, zero_init);
+ }
+ array_add(&lvals, lval);
+ }
+
+ for_array(i, vd->values) {
+ Ast *rhs = unparen_expr(vd->values[i]);
+
+ auto prev_hint = lb_set_copy_elision_hint(p, lvals[i], rhs);
+
+ lbValue init = lb_build_expr(p, rhs);
+ Type *t = init.type;
+ GB_ASSERT(t->kind != Type_Tuple);
+ array_add(&inits, init);
+
+ if (p->copy_elision_hint.used) {
+ lvals[i] = {}; // zero lval
+ }
+ lb_reset_copy_elision_hint(p, prev_hint);
+ }
+
+ for_array(i, inits) {
+ lbAddr lval = lvals[i];
+ lbValue init = inits[i];
+ lb_addr_store(p, lval, init);
+ }
} else { // Tuple(s)
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
auto inits = array_make<lbValue>(permanent_allocator(), 0, vd->names.count);
@@ -5093,13 +5151,15 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
lbAddr lval = {};
if (!is_blank_ident(name)) {
Entity *e = entity_of_node(name);
- lval = lb_add_local(p, e->type, e, false);
+ bool zero_init = false;
+ lval = lb_add_local(p, e->type, e, zero_init);
}
array_add(&lvals, lval);
}
for_array(i, vd->values) {
- lbValue init = lb_build_expr(p, vd->values[i]);
+ Ast *rhs = unparen_expr(vd->values[i]);
+ lbValue init = lb_build_expr(p, rhs);
Type *t = init.type;
if (t->kind == Type_Tuple) {
for_array(i, t->Tuple.variables) {
@@ -5112,7 +5172,6 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
}
}
-
for_array(i, inits) {
lbAddr lval = lvals[i];
lbValue init = inits[i];
@@ -5135,24 +5194,26 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
}
if (as->lhs.count == as->rhs.count) {
- if (as->lhs.count == 1) {
- lbAddr lval = lvals[0];
- Ast *rhs = as->rhs[0];
+ auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
+
+ for_array(i, as->rhs) {
+ Ast *rhs = unparen_expr(as->rhs[i]);
+
+ auto prev_hint = lb_set_copy_elision_hint(p, lvals[i], rhs);
+
lbValue init = lb_build_expr(p, rhs);
- lb_addr_store(p, lvals[0], init);
- } else {
- auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
+ array_add(&inits, init);
- for_array(i, as->rhs) {
- lbValue init = lb_build_expr(p, as->rhs[i]);
- array_add(&inits, init);
+ if (p->copy_elision_hint.used) {
+ lvals[i] = {}; // zero lval
}
+ lb_reset_copy_elision_hint(p, prev_hint);
+ }
- for_array(i, inits) {
- lbAddr lval = lvals[i];
- lbValue init = inits[i];
- lb_addr_store(p, lval, init);
- }
+ for_array(i, inits) {
+ lbAddr lval = lvals[i];
+ lbValue init = inits[i];
+ lb_addr_store(p, lval, init);
}
} else {
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
@@ -8426,7 +8487,7 @@ lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue>
return lb_emit_call(p, proc, args);
}
-lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, bool use_return_ptr_hint) {
+lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, bool use_copy_elision_hint) {
lbModule *m = p->module;
Type *pt = base_type(value.type);
@@ -8532,10 +8593,13 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
Type *rt = reduce_tuple_to_single_type(results);
if (return_by_pointer) {
lbValue return_ptr = {};
- if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) {
- if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) {
- return_ptr = p->return_ptr_hint_value;
- p->return_ptr_hint_used = true;
+ if (use_copy_elision_hint && p->copy_elision_hint.ptr.value != nullptr) {
+ if (are_types_identical(type_deref(p->copy_elision_hint.ptr.type), rt)) {
+ return_ptr = p->copy_elision_hint.ptr;
+ p->copy_elision_hint.used = true;
+ // consume it
+ p->copy_elision_hint.ptr = {};
+ p->copy_elision_hint.ast = nullptr;
}
}
if (return_ptr.value == nullptr) {
@@ -9958,7 +10022,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
}
}
- return lb_emit_call(p, value, args, ce->inlining, p->return_ptr_hint_ast == expr);
+ return lb_emit_call(p, value, args, ce->inlining, p->copy_elision_hint.ast == expr);
}
isize arg_index = 0;
@@ -10140,7 +10204,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
}
auto call_args = array_slice(args, 0, final_count);
- return lb_emit_call(p, value, call_args, ce->inlining, p->return_ptr_hint_ast == expr);
+ return lb_emit_call(p, value, call_args, ce->inlining, p->copy_elision_hint.ast == expr);
}
bool lb_is_const(lbValue value) {
@@ -12751,18 +12815,10 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
}
for_array(i, temp_data) {
- auto return_ptr_hint_ast = p->return_ptr_hint_ast;
- auto return_ptr_hint_value = p->return_ptr_hint_value;
- auto return_ptr_hint_used = p->return_ptr_hint_used;
- defer (p->return_ptr_hint_ast = return_ptr_hint_ast);
- defer (p->return_ptr_hint_value = return_ptr_hint_value);
- defer (p->return_ptr_hint_used = return_ptr_hint_used);
-
lbValue field_expr = temp_data[i].value;
Ast *expr = temp_data[i].expr;
- p->return_ptr_hint_value = temp_data[i].gep;
- p->return_ptr_hint_ast = unparen_expr(expr);
+ auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr);
if (field_expr.value == nullptr) {
field_expr = lb_build_expr(p, expr);
@@ -12771,9 +12827,11 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
GB_ASSERT(t->kind != Type_Tuple);
lbValue ev = lb_emit_conv(p, field_expr, et);
- if (!p->return_ptr_hint_used) {
+ if (!p->copy_elision_hint.used) {
temp_data[i].value = ev;
}
+
+ lb_reset_copy_elision_hint(p, prev_hint);
}
for_array(i, temp_data) {
@@ -12854,18 +12912,10 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
}
for_array(i, temp_data) {
- auto return_ptr_hint_ast = p->return_ptr_hint_ast;
- auto return_ptr_hint_value = p->return_ptr_hint_value;
- auto return_ptr_hint_used = p->return_ptr_hint_used;
- defer (p->return_ptr_hint_ast = return_ptr_hint_ast);
- defer (p->return_ptr_hint_value = return_ptr_hint_value);
- defer (p->return_ptr_hint_used = return_ptr_hint_used);
-
lbValue field_expr = temp_data[i].value;
Ast *expr = temp_data[i].expr;
- p->return_ptr_hint_value = temp_data[i].gep;
- p->return_ptr_hint_ast = unparen_expr(expr);
+ auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr);
if (field_expr.value == nullptr) {
field_expr = lb_build_expr(p, expr);
@@ -12874,9 +12924,11 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
GB_ASSERT(t->kind != Type_Tuple);
lbValue ev = lb_emit_conv(p, field_expr, et);
- if (!p->return_ptr_hint_used) {
+ if (!p->copy_elision_hint.used) {
temp_data[i].value = ev;
}
+
+ lb_reset_copy_elision_hint(p, prev_hint);
}
for_array(i, temp_data) {