aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend_stmt.cpp
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2022-12-07 11:42:23 +0000
committerGitHub <noreply@github.com>2022-12-07 11:42:23 +0000
commita5bdb4a8e85f955ea660bd66b2c1c5990ab46c03 (patch)
tree9cc0fe9c6a7b7cd4728bafc21b5252372d131d52 /src/llvm_backend_stmt.cpp
parent521ed286321a30e5742a432effefb2c98b9484a7 (diff)
parentd88b052d2d9aa8fa012be314bd29d7ae311fc941 (diff)
Merge pull request #2208 from odin-lang/multiple-return-abi-experiment
Multiple Return ABI Changes and Improvements
Diffstat (limited to 'src/llvm_backend_stmt.cpp')
-rw-r--r--src/llvm_backend_stmt.cpp171
1 files changed, 88 insertions, 83 deletions
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index c8f244181..46144aa00 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -1,31 +1,3 @@
-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 0
- 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);
- }
- #endif
- return prev;
-}
-
-void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint) {
- p->copy_elision_hint = prev_hint;
-}
-
-
-lbValue lb_consume_copy_elision_hint(lbProcedure *p) {
- lbValue return_ptr = p->copy_elision_hint.ptr;
- p->copy_elision_hint.used = true;
- p->copy_elision_hint.ptr = {};
- p->copy_elision_hint.ast = nullptr;
- return return_ptr;
-}
-
-
void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
if (vd == nullptr || vd->is_mutable) {
return;
@@ -726,13 +698,13 @@ void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1
i32 tuple_count = cast(i32)tuple->Tuple.variables.count;
i32 cond_index = tuple_count-1;
- lbValue cond = lb_emit_struct_ev(p, tuple_value, cond_index);
+ lbValue cond = lb_emit_tuple_ev(p, tuple_value, cond_index);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
- if (val0_) *val0_ = lb_emit_struct_ev(p, tuple_value, 0);
- if (val1_) *val1_ = lb_emit_struct_ev(p, tuple_value, 1);
+ if (val0_) *val0_ = lb_emit_tuple_ev(p, tuple_value, 0);
+ if (val1_) *val1_ = lb_emit_tuple_ev(p, tuple_value, 1);
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
@@ -1571,6 +1543,24 @@ void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
lb_add_member(p->module, mangled_name, global_val);
}
}
+void lb_append_tuple_values(lbProcedure *p, Array<lbValue> *dst_values, lbValue src_value) {
+ Type *t = src_value.type;
+ if (t->kind == Type_Tuple) {
+ lbTupleFix *tf = map_get(&p->tuple_fix_map, src_value.value);
+ if (tf) {
+ for_array(j, tf->values) {
+ array_add(dst_values, tf->values[j]);
+ }
+ } else {
+ for_array(i, t->Tuple.variables) {
+ lbValue v = lb_emit_tuple_ev(p, src_value, cast(i32)i);
+ array_add(dst_values, v);
+ }
+ }
+ } else {
+ array_add(dst_values, src_value);
+ }
+}
void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> const &values) {
@@ -1582,23 +1572,8 @@ void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> cons
for_array(i, values) {
Ast *rhs = values[i];
- if (is_type_tuple(type_of_expr(rhs))) {
- lbValue init = lb_build_expr(p, rhs);
- Type *t = init.type;
- GB_ASSERT(t->kind == Type_Tuple);
- for_array(i, t->Tuple.variables) {
- lbValue v = lb_emit_struct_ev(p, init, cast(i32)i);
- array_add(&inits, v);
- }
- } else {
- auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs);
- lbValue init = lb_build_expr(p, rhs);
- if (p->copy_elision_hint.used) {
- lvals[inits.count] = {}; // zero lval
- }
- lb_reset_copy_elision_hint(p, prev_hint);
- array_add(&inits, init);
- }
+ lbValue init = lb_build_expr(p, rhs);
+ lb_append_tuple_values(p, &inits, init);
}
GB_ASSERT(lvals.count == inits.count);
@@ -1609,9 +1584,14 @@ void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> cons
}
}
-void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) {
- lbFunctionType *ft = lb_get_function_type(p->module, p, p->type);
+void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
+ lbFunctionType *ft = lb_get_function_type(p->module, p->type);
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
+ bool split_returns = ft->multiple_return_original_type != nullptr;
+
+ if (split_returns) {
+ GB_ASSERT(res.value == nullptr || !is_type_tuple(res.type));
+ }
if (return_by_pointer) {
if (res.value != nullptr) {
@@ -1650,7 +1630,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
isize return_count = p->type->Proc.result_count;
isize res_count = return_results.count;
- lbFunctionType *ft = lb_get_function_type(p->module, p, p->type);
+ lbFunctionType *ft = lb_get_function_type(p->module, p->type);
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
if (return_count == 0) {
@@ -1683,15 +1663,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
if (res_count != 0) {
for (isize res_index = 0; res_index < res_count; res_index++) {
lbValue res = lb_build_expr(p, return_results[res_index]);
- Type *t = res.type;
- if (t->kind == Type_Tuple) {
- for_array(i, t->Tuple.variables) {
- lbValue v = lb_emit_struct_ev(p, res, cast(i32)i);
- array_add(&results, v);
- }
- } else {
- array_add(&results, res);
- }
+ lb_append_tuple_values(p, &results, res);
}
} else {
for (isize res_index = 0; res_index < return_count; res_index++) {
@@ -1727,35 +1699,68 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
}
}
- Type *ret_type = p->type->Proc.results;
+ bool split_returns = ft->multiple_return_original_type != nullptr;
+ if (split_returns) {
+ auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
+ auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count-1);
+
+ for_array(i, results) {
+ result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
+ }
+
+ isize param_offset = return_by_pointer ? 1 : 0;
+ param_offset += ft->original_arg_count;
+ for_array(i, result_eps) {
+ lbValue result_ep = {};
+ result_ep.value = LLVMGetParam(p->value, cast(unsigned)(param_offset+i));
+ result_ep.type = alloc_type_pointer(tuple->variables[i]->type);
+ result_eps[i] = result_ep;
+ }
+ for_array(i, result_eps) {
+ lb_emit_store(p, result_eps[i], result_values[i]);
+ }
+ if (return_by_pointer) {
+ GB_ASSERT(result_values.count-1 == result_eps.count);
+ lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]);
+
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ LLVMBuildRetVoid(p->builder);
+ return;
+ } else {
+ return lb_build_return_stmt_internal(p, result_values[result_values.count-1]);
+ }
- // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
- if (return_by_pointer) {
- res = p->return_ptr.addr;
} else {
- res = lb_add_local_generated(p, ret_type, false).addr;
- }
+ Type *ret_type = p->type->Proc.results;
+
+ // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
+ if (return_by_pointer) {
+ res = p->return_ptr.addr;
+ } else {
+ res = lb_add_local_generated(p, ret_type, false).addr;
+ }
- auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
- auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count);
+ auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
+ auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count);
- for_array(i, results) {
- result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
- }
- for_array(i, results) {
- result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
- }
- for_array(i, result_values) {
- lb_emit_store(p, result_eps[i], result_values[i]);
- }
+ for_array(i, results) {
+ result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
+ }
+ for_array(i, results) {
+ result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
+ }
+ for_array(i, result_eps) {
+ lb_emit_store(p, result_eps[i], result_values[i]);
+ }
- if (return_by_pointer) {
- lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
- LLVMBuildRetVoid(p->builder);
- return;
- }
+ if (return_by_pointer) {
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ LLVMBuildRetVoid(p->builder);
+ return;
+ }
- res = lb_emit_load(p, res);
+ res = lb_emit_load(p, res);
+ }
}
lb_build_return_stmt_internal(p, res);
}