Skip to content

Commit

Permalink
copy elision: while-optional with aggregate
Browse files Browse the repository at this point in the history
```zig
export fn entry() void {
    var c = false;
    var x: ?Foo = foo();
    var z = while (x) |a| {
        _ = if (c) break a.y;
    } else bar();
}
```

```llvm
define void @entry() #2 !dbg !41 {
Entry:
  %c = alloca i1, align 1
  %x = alloca { %Foo, i1 }, align 4
  %z = alloca %Bar, align 4
  store i1 false, i1* %c, align 1, !dbg !66
  call void @llvm.dbg.declare(metadata i1* %c, metadata !45, metadata !DIExpression()), !dbg !67
  %0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !68
  store i1 true, i1* %0, align 1, !dbg !68
  %1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !68
  call fastcc void @foo(%Foo* sret %1), !dbg !69
  call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !48, metadata !DIExpression()), !dbg !68
  br label %WhileCond, !dbg !70

WhileCond:                                        ; preds = %Else, %Entry
  %2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !71
  %3 = load i1, i1* %2, align 1, !dbg !71
  br i1 %3, label %WhileBody, label %WhileElse, !dbg !71

WhileBody:                                        ; preds = %WhileCond
  %4 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !72
  call void @llvm.dbg.declare(metadata %Foo* %4, metadata !63, metadata !DIExpression()), !dbg !70
  %5 = load i1, i1* %c, align 1, !dbg !74
  br i1 %5, label %Then, label %Else, !dbg !74

Then:                                             ; preds = %WhileBody
  %6 = getelementptr inbounds %Foo, %Foo* %4, i32 0, i32 1, !dbg !76
  %7 = bitcast %Bar* %6 to i8*, !dbg !76
  %8 = bitcast %Bar* %z to i8*, !dbg !76
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %8, i8* align 4 %7, i64 8, i1 false), !dbg !76
  br label %WhileEnd, !dbg !77

Else:                                             ; preds = %WhileBody
  br label %WhileCond, !dbg !72

WhileElse:                                        ; preds = %WhileCond
  call fastcc void @bar(%Bar* sret %z), !dbg !78
  br label %WhileEnd, !dbg !70

WhileEnd:                                         ; preds = %WhileElse, %Then
  call void @llvm.dbg.declare(metadata %Bar* %z, metadata !65, metadata !DIExpression()), !dbg !79
  ret void, !dbg !80
}
```
  • Loading branch information
andrewrk committed Oct 30, 2018
1 parent a694363 commit 00a5b72
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 59 deletions.
6 changes: 4 additions & 2 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6322,8 +6322,10 @@ static void do_code_gen(CodeGen *g) {
ZigType *ptr_type = instruction->base.value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *child_type = ptr_type->data.pointer.child_type;
instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
get_ptr_align(g, ptr_type));
if (type_has_bits(child_type)) {
instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
get_ptr_align(g, ptr_type));
}
}

ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
Expand Down
99 changes: 42 additions & 57 deletions src/ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5323,7 +5323,9 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, alloca);
}

static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
assert(node->type == NodeTypeWhileExpr);

AstNode *continue_expr_node = node->data.while_expr.continue_expr;
Expand Down Expand Up @@ -5358,26 +5360,29 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
} else {
payload_scope = subexpr_scope;
}
IrInstruction *err_val_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
IrInstruction *err_union_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
LValPtr, nullptr);
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr, nullptr);
IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
if (type_is_invalid(err_union_ptr->value.type))
return err_union_ptr;

IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope,
node->data.while_expr.condition, err_union_ptr);
IrInstruction *opt_err_code = ir_build_load_ptr(irb, scope, node->data.while_expr.condition,
ptr_opt_err_code, nullptr);
IrInstruction *is_err = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, opt_err_code);

if (!instr_is_unreachable(is_err)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
else_block, body_block, is_comptime));
}

ir_set_cursor_at_end_and_append_block(irb, body_block);
if (var_symbol) {
IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
err_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
ir_build_ref(irb, payload_scope, symbol_node, var_ptr_value, true, false) : var_ptr_value;
ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
err_union_ptr, false);
IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);
}

ZigList<IrInstruction *> incoming_values = {0};
Expand Down Expand Up @@ -5419,26 +5424,19 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
true, false, false, is_comptime);
Scope *err_scope = err_var->child_scope;
IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, err_scope, err_symbol_node,
ptr_opt_err_code, false);
ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, unwrapped_err_code_ptr);

else_result = ir_gen_node(irb, else_node, err_scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
IrBasicBlock *after_else_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, end_block);
if (else_result) {
incoming_blocks.append(after_else_block);
incoming_values.append(else_result);
} else {
incoming_blocks.append(after_cond_block);
incoming_values.append(void_else_result);
}

return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
ir_set_cursor_at_end_and_append_block(irb, end_block);
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
} else if (var_symbol != nullptr) {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
Expand All @@ -5454,18 +5452,16 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
return maybe_val_ptr;
IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
if (!instr_is_unreachable(is_non_null)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,
body_block, else_block, is_comptime));
}

ir_set_cursor_at_end_and_append_block(irb, body_block);
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
ir_build_ref(irb, child_scope, symbol_node, var_ptr_value, true, false) : var_ptr_value;
ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);

ZigList<IrInstruction *> incoming_values = {0};
ZigList<IrBasicBlock *> incoming_blocks = {0};
Expand All @@ -5480,7 +5476,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n

IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
LValNone, result_loc);
if (body_result == irb->codegen->invalid_instruction)
if (type_is_invalid(body_result->value.type))
return body_result;

if (!instr_is_unreachable(body_result)) {
Expand All @@ -5507,24 +5503,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
IrBasicBlock *after_else_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, end_block);
if (else_result) {
incoming_blocks.append(after_else_block);
incoming_values.append(else_result);
} else {
incoming_blocks.append(after_cond_block);
incoming_values.append(void_else_result);
}

return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
} else {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope, LValNone, nullptr);
if (cond_val == irb->codegen->invalid_instruction)
return cond_val;
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
if (!instr_is_unreachable(cond_val)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
body_block, else_block, is_comptime));
Expand Down Expand Up @@ -5574,17 +5559,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
IrBasicBlock *after_else_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, end_block);
if (else_result) {
incoming_blocks.append(after_else_block);
incoming_values.append(else_result);
} else {
incoming_blocks.append(after_cond_block);
incoming_values.append(void_else_result);
}

return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
ir_set_cursor_at_end_and_append_block(irb, end_block);
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
}
}

Expand Down Expand Up @@ -5944,7 +5921,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
Buf *err_symbol = node->data.if_err_expr.err_symbol;

IrInstruction *err_union_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
if (err_union_ptr == irb->codegen->invalid_instruction)
if (type_is_invalid(err_union_ptr->value.type))
return err_union_ptr;

IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope, node, err_union_ptr);
Expand Down Expand Up @@ -7216,6 +7193,12 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
}

static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
if (result_loc)
return result_loc;
return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
}

static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
IrInstruction *result_loc)
{
Expand Down Expand Up @@ -7248,15 +7231,17 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeFnCallExpr:
return ir_gen_fn_call(irb, scope, node, lval, result_loc);
case NodeTypeIfBoolExpr:
return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc);
return ir_gen_if_bool_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, scope, node, lval);
case NodeTypeContainerInitExpr:
return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node, result_loc), lval);
case NodeTypeVariableDeclaration:
return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval);
case NodeTypeWhileExpr:
return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node, result_loc), lval);
return ir_gen_while_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeForExpr:
return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node, result_loc), lval);
case NodeTypeArrayAccessExpr:
Expand Down

0 comments on commit 00a5b72

Please sign in to comment.