Skip to content

Commit 1bda970

Browse files
committed
copy elision: if-optional with aggregate
```zig export fn entry() void { var x: ?Foo = foo(); var y = if (x) |a| a.y else bar(); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca { %Foo, i1 }, align 4 %y = alloca %Bar, align 4 %0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !64 store i1 true, i1* %0, align 1, !dbg !64 %1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !64 call fastcc void @foo(%Foo* sret %1), !dbg !65 call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !45, metadata !DIExpression()), !dbg !64 %2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !66 %3 = load i1, i1* %2, align 1, !dbg !66 br i1 %3, label %OptionalThen, label %OptionalElse, !dbg !66 OptionalThen: ; preds = %Entry %4 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !66 call void @llvm.dbg.declare(metadata %Foo* %4, metadata !61, metadata !DIExpression()), !dbg !66 %5 = getelementptr inbounds %Foo, %Foo* %4, i32 0, i32 1, !dbg !67 %6 = bitcast %Bar* %5 to i8*, !dbg !67 %7 = bitcast %Bar* %y to i8*, !dbg !67 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %6, i64 8, i1 false), !dbg !67 br label %OptionalEndIf, !dbg !66 OptionalElse: ; preds = %Entry call fastcc void @bar(%Bar* sret %y), !dbg !69 br label %OptionalEndIf, !dbg !66 OptionalEndIf: ; preds = %OptionalElse, %OptionalThen call void @llvm.dbg.declare(metadata %Bar* %y, metadata !63, metadata !DIExpression()), !dbg !70 ret void, !dbg !71 } ```
1 parent 94abb0d commit 1bda970

File tree

2 files changed

+15
-30
lines changed

2 files changed

+15
-30
lines changed

src/ir.cpp

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3832,7 +3832,9 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
38323832
return ir_build_load_result(irb, scope, node, ptr_instruction, result_loc);
38333833
}
38343834

3835-
static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) {
3835+
static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
3836+
IrInstruction *result_loc)
3837+
{
38363838
assert(node->type == NodeTypeFieldAccessExpr);
38373839

38383840
AstNode *container_ref_node = node->data.field_access_expr.struct_expr;
@@ -3842,7 +3844,8 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode
38423844
if (container_ref_instruction == irb->codegen->invalid_instruction)
38433845
return container_ref_instruction;
38443846

3845-
return ir_build_field_ptr(irb, scope, node, container_ref_instruction, nullptr, field_name);
3847+
IrInstruction *field_ptr = ir_build_field_ptr(irb, scope, node, container_ref_instruction, nullptr, field_name);
3848+
return ir_gen_ptr(irb, scope, node, lval, result_loc, field_ptr);
38463849
}
38473850

38483851
static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) {
@@ -5856,7 +5859,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
58565859
return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile);
58575860
}
58585861

5859-
static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node,
5862+
static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
58605863
IrInstruction *result_loc)
58615864
{
58625865
assert(node->type == NodeTypeIfOptional);
@@ -5897,20 +5900,17 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
58975900
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
58985901
var_symbol, is_const, is_const, is_shadowable, is_comptime);
58995902

5900-
IrInstruction *payload_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "optional_payload");
5901-
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
5902-
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_result(irb, subexpr_scope, node,
5903-
var_ptr_value, payload_alloca);
5904-
ir_build_store_result(irb, subexpr_scope, node, payload_alloca, var_value);
5905-
ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, payload_alloca);
5903+
IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
5904+
IrInstruction *var_ptr = var_is_ptr ?
5905+
ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;
5906+
ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_ptr);
59065907
var_scope = var->child_scope;
59075908
} else {
59085909
var_scope = subexpr_scope;
59095910
}
59105911
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope, LValNone, result_loc);
59115912
if (then_expr_result == irb->codegen->invalid_instruction)
59125913
return then_expr_result;
5913-
IrBasicBlock *after_then_block = irb->current_basic_block;
59145914
if (!instr_is_unreachable(then_expr_result))
59155915
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
59165916

@@ -5923,19 +5923,11 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
59235923
} else {
59245924
else_expr_result = ir_build_const_void(irb, scope, node);
59255925
}
5926-
IrBasicBlock *after_else_block = irb->current_basic_block;
59275926
if (!instr_is_unreachable(else_expr_result))
59285927
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
59295928

59305929
ir_set_cursor_at_end_and_append_block(irb, endif_block);
5931-
IrInstruction **incoming_values = allocate<IrInstruction *>(2);
5932-
incoming_values[0] = then_expr_result;
5933-
incoming_values[1] = else_expr_result;
5934-
IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
5935-
incoming_blocks[0] = after_then_block;
5936-
incoming_blocks[1] = after_else_block;
5937-
5938-
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
5930+
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
59395931
}
59405932

59415933
static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
@@ -7276,15 +7268,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
72767268
case NodeTypeReturnExpr:
72777269
return ir_gen_return(irb, scope, node, lval, result_loc);
72787270
case NodeTypeFieldAccessExpr:
7279-
{
7280-
IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node);
7281-
if (ptr_instruction == irb->codegen->invalid_instruction)
7282-
return ptr_instruction;
7283-
if (lval == LValPtr)
7284-
return ptr_instruction;
7285-
7286-
return ir_build_load_ptr(irb, scope, node, ptr_instruction, nullptr);
7287-
}
7271+
return ir_gen_field_access(irb, scope, node, lval, result_loc);
72887272
case NodeTypePtrDeref: {
72897273
AstNode *expr_node = node->data.ptr_deref_expr.target;
72907274
IrInstruction *value = ir_gen_node(irb, expr_node, scope, lval, nullptr);
@@ -7325,7 +7309,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
73257309
case NodeTypeIfErrorExpr:
73267310
return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node, result_loc), lval);
73277311
case NodeTypeIfOptional:
7328-
return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node, result_loc), lval);
7312+
return ir_gen_if_optional_expr(irb, scope, node, lval, result_loc);
73297313
case NodeTypeSwitchExpr:
73307314
return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node, result_loc), lval);
73317315
case NodeTypeCompTime:

src/ir_print.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,9 @@ static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instructi
491491
}
492492

493493
static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
494-
fprintf(irp->f, "&??*");
494+
fprintf(irp->f, "UnwrapOptional(");
495495
ir_print_other_instruction(irp, instruction->value);
496+
fprintf(irp->f, ")");
496497
if (!instruction->safety_check_on) {
497498
fprintf(irp->f, " // no safety");
498499
}

0 commit comments

Comments
 (0)