aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-11-13 22:55:32 +0000
committergingerBill <bill@gingerbill.org>2022-11-13 22:55:32 +0000
commita705a2e38bee035d6800999ba6eddd82792594f7 (patch)
tree9beece2552d41ad12489e7cfaf73df80bbf6fb95 /src
parent7dfbda58d9c51932fa91a04727b821860358289d (diff)
Minor improvement to multi return value reducing stack usage
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp3
-rw-r--r--src/check_stmt.cpp4
-rw-r--r--src/checker.hpp1
-rw-r--r--src/llvm_backend_general.cpp24
-rw-r--r--src/llvm_backend_opt.cpp35
-rw-r--r--src/llvm_backend_proc.cpp42
6 files changed, 90 insertions, 19 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index c58aac609..c819267fd 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -6739,6 +6739,9 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr
if (initial_entity != nullptr && initial_entity->kind == Entity_Procedure) {
if (initial_entity->Procedure.deferred_procedure.entity != nullptr) {
call->viral_state_flags |= ViralStateFlag_ContainsDeferredProcedure;
+ if (c->decl != nullptr) {
+ c->decl->defer_use_count += 1;
+ }
}
}
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 9cacb4a35..8271ca451 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -2014,6 +2014,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (is_ast_decl(ds->stmt)) {
error(ds->token, "You cannot defer a declaration");
} else {
+ if (ctx->decl != nullptr) {
+ ctx->decl->defer_use_count += 1;
+ }
+
bool out_in_defer = ctx->in_defer;
ctx->in_defer = true;
check_stmt(ctx, ds->stmt, 0);
diff --git a/src/checker.hpp b/src/checker.hpp
index badcd93d5..ded4a0ad6 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -158,6 +158,7 @@ struct DeclInfo {
bool is_using;
bool where_clauses_evaluated;
bool proc_checked;
+ isize defer_use_count;
CommentGroup *comment;
CommentGroup *docs;
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index f36dc1842..6f2253d01 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -936,23 +936,27 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0);
LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), "");
- LLVMBuildMemMove(p->builder,
- dst_ptr, lb_try_get_alignment(dst_ptr, 1),
- src_ptr, lb_try_get_alignment(src_ptr_original, 1),
- LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
+ if (dst_ptr != src_ptr && dst_ptr != src_ptr_original) {
+ LLVMBuildMemMove(p->builder,
+ dst_ptr, lb_try_get_alignment(dst_ptr, 1),
+ src_ptr, lb_try_get_alignment(src_ptr_original, 1),
+ LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
+ }
return;
} else if (LLVMIsConstant(value.value)) {
lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
lb_make_global_private_const(addr);
LLVMValueRef dst_ptr = ptr.value;
- LLVMValueRef src_ptr = addr.addr.value;
- src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
+ LLVMValueRef src_ptr_original = addr.addr.value;
+ LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), "");
- LLVMBuildMemMove(p->builder,
- dst_ptr, lb_try_get_alignment(dst_ptr, 1),
- src_ptr, lb_try_get_alignment(src_ptr, 1),
- LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
+ if (dst_ptr != src_ptr && dst_ptr != src_ptr_original) {
+ LLVMBuildMemMove(p->builder,
+ dst_ptr, lb_try_get_alignment(dst_ptr, 1),
+ src_ptr, lb_try_get_alignment(src_ptr, 1),
+ LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
+ }
return;
}
}
diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp
index e2f51b868..ba5a41871 100644
--- a/src/llvm_backend_opt.cpp
+++ b/src/llvm_backend_opt.cpp
@@ -267,6 +267,8 @@ void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPa
**************************************************************************/
void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
+ LLVMTypeRef llvm_void = LLVMVoidTypeInContext(p->module->ctx);
+
isize removal_count = 0;
isize pass_count = 0;
isize const max_pass_count = 10;
@@ -322,7 +324,7 @@ void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
case LLVMOr:
case LLVMXor:
case LLVMAlloca:
- case LLVMLoad:
+ case LLVMLoad: // TODO: should LLVMLoad be removed?
case LLVMGetElementPtr:
case LLVMTrunc:
case LLVMZExt:
@@ -347,6 +349,37 @@ void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
LLVMInstructionEraseFromParent(curr_instr);
was_dead_instructions = true;
break;
+
+ case LLVMCall:
+ if (LLVMTypeOf(curr_instr) == llvm_void) {
+ LLVMValueRef the_proc = LLVMGetCalledValue(curr_instr);
+ unsigned id = LLVMGetIntrinsicID(the_proc);
+ if (id != 0) {
+ size_t text_len = 0;
+ char const *text = LLVMIntrinsicGetName(id, &text_len);
+ String name = make_string(cast(u8 const *)text, cast(isize)text_len);
+ if (name == "llvm.memmove" || name == "llvm.memcpy") {
+ LLVMValueRef dst = LLVMGetOperand(curr_instr, 0);
+ LLVMValueRef src = LLVMGetOperand(curr_instr, 1);
+ LLVMValueRef sz = LLVMGetOperand(curr_instr, 2);
+ if ((dst == src) || (LLVMIsConstant(sz) && LLVMConstIntGetZExtValue(sz) == 0)) {
+ removal_count += 1;
+ LLVMInstructionEraseFromParent(curr_instr);
+ was_dead_instructions = true;
+ break;
+ }
+ } else if (name == "llvm.memset") {
+ LLVMValueRef sz = LLVMGetOperand(curr_instr, 2);
+ if (LLVMIsConstant(sz) && LLVMConstIntGetZExtValue(sz) == 0) {
+ removal_count += 1;
+ LLVMInstructionEraseFromParent(curr_instr);
+ was_dead_instructions = true;
+ break;
+ }
+ }
+ }
+ }
+ break;
}
}
}
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index eaff6edc0..2e508a939 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -9,9 +9,15 @@ LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* a
}
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
+ if (dst.value == src.value) {
+ return;
+ }
dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr);
len = lb_emit_conv(p, len, t_int);
+ if (dst.value == src.value) {
+ return;
+ }
char const *name = "llvm.memmove";
if (LLVMIsConstant(len.value)) {
@@ -38,9 +44,16 @@ void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue l
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
+ if (dst.value == src.value) {
+ return;
+ }
dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr);
len = lb_emit_conv(p, len, t_int);
+ if (dst.value == src.value) {
+ return;
+ }
+
char const *name = "llvm.memcpy";
if (LLVMIsConstant(len.value)) {
@@ -580,18 +593,31 @@ void lb_begin_procedure_body(lbProcedure *p) {
if (e->token.string != "") {
GB_ASSERT(!is_blank_ident(e->token));
- // NOTE(bill): Don't even bother trying to optimize this with the return ptr value
- // This will violate the defer rules if you do:
- // foo :: proc() -> (x, y: T) {
- // defer x = ... // defer is executed after the `defer`
- // return // the values returned should be zeroed
- // }
- lbAddr res = lb_add_local(p, e->type, e);
+ lbAddr res = {};
+ if (p->return_ptr.addr.value != nullptr &&
+ p->entity != nullptr &&
+ p->entity->decl_info != nullptr &&
+ p->entity->decl_info->defer_use_count == 0) {
+ lbValue val = lb_emit_struct_ep(p, p->return_ptr.addr, cast(i32)i);
+
+ lb_add_entity(p->module, e, val);
+ lb_add_debug_local_variable(p, val.value, e->type, e->token);
+
+ // NOTE(bill): no need to zero initialize due to caller will zero return value
+ res = lb_addr(val);
+ } else {
+ // NOTE(bill): Don't even bother trying to optimize this with the return ptr value
+ // This will violate the defer rules if you do:
+ // foo :: proc() -> (x, y: T) {
+ // defer x = ... // defer is executed after the `defer`
+ // return // the values returned should be zeroed
+ // }
+ res = lb_add_local(p, e->type, e);
+ }
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
lb_addr_store(p, res, c);
}
-
}
}