Skip to content

Commit

Permalink
copy elision: implicit cast error set to error union
Browse files Browse the repository at this point in the history
```zig
export fn entry() void {
    var x: error!Foo = fail();
}
```

```llvm
define void @entry() #2 !dbg !42 {
Entry:
  %x = alloca { i16, %Foo }, align 4
  %0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !57
  %1 = call fastcc i16 @fail(), !dbg !58
  store i16 %1, i16* %0, align 2, !dbg !58
  ret void, !dbg !59
}
```
  • Loading branch information
andrewrk committed Oct 30, 2018
1 parent 7608505 commit 5106eac
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 69 deletions.
7 changes: 7 additions & 0 deletions src/all_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2175,6 +2175,7 @@ enum IrInstructionId {
IrInstructionIdCheckRuntimeScope,
IrInstructionIdResultOptionalPayload,
IrInstructionIdResultErrorUnionPayload,
IrInstructionIdResultErrorUnionCode,
IrInstructionIdResultReturn,
IrInstructionIdResultBytesToSlice,
IrInstructionIdResultSliceToBytes,
Expand Down Expand Up @@ -3298,6 +3299,12 @@ struct IrInstructionResultErrorUnionPayload {
IrInstruction *prev_result_loc;
};

struct IrInstructionResultErrorUnionCode {
IrInstruction base;

IrInstruction *prev_result_loc;
};

struct IrInstructionResultOptionalPayload {
IrInstruction base;

Expand Down
10 changes: 10 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5118,6 +5118,14 @@ static LLVMValueRef ir_render_result_error_union_payload(CodeGen *g, IrExecutabl
return LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_payload_index, "");
}

static LLVMValueRef ir_render_result_error_union_code(CodeGen *g, IrExecutable *executable,
IrInstructionResultErrorUnionCode *instruction)
{
LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
// TODO write 0xaa in debug mode to the undefined payload
return LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_err_index, "");
}

static LLVMValueRef ir_render_assert_non_error(CodeGen *g, IrExecutable *executable,
IrInstructionAssertNonError *instruction)
{
Expand Down Expand Up @@ -5383,6 +5391,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_result_optional_payload(g, executable, (IrInstructionResultOptionalPayload *)instruction);
case IrInstructionIdResultErrorUnionPayload:
return ir_render_result_error_union_payload(g, executable, (IrInstructionResultErrorUnionPayload *)instruction);
case IrInstructionIdResultErrorUnionCode:
return ir_render_result_error_union_code(g, executable, (IrInstructionResultErrorUnionCode *)instruction);
case IrInstructionIdAssertNonError:
return ir_render_assert_non_error(g, executable, (IrInstructionAssertNonError *)instruction);
case IrInstructionIdResultSliceToBytes:
Expand Down
178 changes: 109 additions & 69 deletions src/ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnion
return IrInstructionIdResultErrorUnionPayload;
}

static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnionCode *) {
return IrInstructionIdResultErrorUnionCode;
}

static constexpr IrInstructionId ir_instruction_id(IrInstructionResultOptionalPayload *) {
return IrInstructionIdResultOptionalPayload;
}
Expand Down Expand Up @@ -2816,6 +2820,17 @@ static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope
return &instruction->base;
}

static IrInstruction *ir_build_result_error_union_code(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *prev_result_loc)
{
IrInstructionResultErrorUnionCode *instruction = ir_build_instruction<IrInstructionResultErrorUnionCode>(irb, scope, source_node);
instruction->prev_result_loc = prev_result_loc;

ir_ref_instruction(prev_result_loc, irb->current_basic_block);

return &instruction->base;
}

static IrInstruction *ir_build_result_return(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionResultReturn *instruction = ir_build_instruction<IrInstructionResultReturn>(irb, scope, source_node);
return &instruction->base;
Expand Down Expand Up @@ -9848,6 +9863,23 @@ static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrIn
return result;
}

static IrInstruction *ir_analyze_result_error_union_code(IrAnalyze *ira, IrInstruction *result_loc,
ZigType *needed_child_type)
{
if (instr_is_comptime(result_loc)) {
zig_panic("TODO comptime ir_analyze_result_error_union_code");
}
ZigType *old_ptr_type = result_loc->value.type;
assert(old_ptr_type->id == ZigTypeIdPointer);
ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);

IrInstruction *result = ir_build_result_error_union_code(&ira->new_irb, result_loc->scope,
result_loc->source_node, result_loc);
result->value.type = new_ptr_type;
return result;
}

static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type)
{
Expand Down Expand Up @@ -11161,6 +11193,13 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
}
}

// cast from E to E!T
if (have_child_type->id == ZigTypeIdErrorUnion &&
needed_child_type->id == ZigTypeIdErrorSet)
{
return ir_analyze_result_error_union_code(ira, result_loc, needed_child_type);
}

ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
buf_sprintf("expected type '%s', found '%s'",
buf_ptr(&have_child_type->name),
Expand Down Expand Up @@ -13251,6 +13290,67 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
return var_ptr_instruction;
}

static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *ptr, IrInstruction *value)
{
Error err;
if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
return ira->codegen->invalid_instruction;

if (ptr->value.type->id != ZigTypeIdPointer) {
ir_add_error(ira, ptr,
buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
return ira->codegen->invalid_instruction;
}

if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
return ir_const_void(ira, source_instr);
}

if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}

ZigType *child_type = ptr->value.type->data.pointer.child_type;
IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
if (casted_value == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;

if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
if (instr_is_comptime(casted_value)) {
ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
if (dest_val == nullptr)
return ira->codegen->invalid_instruction;
if (dest_val->special != ConstValSpecialRuntime) {
*dest_val = casted_value->value;
if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
}
return ir_const_void(ira, source_instr);
}
}
ir_add_error(ira, source_instr,
buf_sprintf("cannot store runtime value in compile time variable"));
ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
dest_val->type = ira->codegen->builtin_types.entry_invalid;

return ira->codegen->invalid_instruction;
}
}

IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
ptr, casted_value);
result->value.type = ira->codegen->builtin_types.entry_void;
return result;
}


static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
Expand Down Expand Up @@ -13795,7 +13895,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call

IrInstruction *result_loc = nullptr;

if (handle_is_ptr(return_type)) {
if (call_instruction->result_loc != nullptr) {
result_loc = ir_implicit_cast_result(ira, call_instruction->result_loc->child, return_type);
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
Expand All @@ -13806,6 +13906,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
casted_new_stack, result_loc);
new_call_instruction->value.type = return_type;

if (!handle_is_ptr(return_type) && result_loc != nullptr) {
ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, new_call_instruction);
}

return ir_finish_anal(ira, new_call_instruction);
}

Expand Down Expand Up @@ -15217,66 +15322,6 @@ static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstr
zig_panic("TODO");
}

static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *ptr, IrInstruction *value)
{
Error err;
if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
return ira->codegen->invalid_instruction;

if (ptr->value.type->id != ZigTypeIdPointer) {
ir_add_error(ira, ptr,
buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
return ira->codegen->invalid_instruction;
}

if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
return ir_const_void(ira, source_instr);
}

if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}

ZigType *child_type = ptr->value.type->data.pointer.child_type;
IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
if (casted_value == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;

if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
if (instr_is_comptime(casted_value)) {
ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
if (dest_val == nullptr)
return ira->codegen->invalid_instruction;
if (dest_val->special != ConstValSpecialRuntime) {
*dest_val = casted_value->value;
if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
}
return ir_const_void(ira, source_instr);
}
}
ir_add_error(ira, source_instr,
buf_sprintf("cannot store runtime value in compile time variable"));
ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
dest_val->type = ira->codegen->builtin_types.entry_invalid;

return ira->codegen->invalid_instruction;
}
}

IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
ptr, casted_value);
result->value.type = ira->codegen->builtin_types.entry_void;
return result;
}

static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
IrInstruction *ptr = instruction->ptr->child;
if (type_is_invalid(ptr->value.type))
Expand Down Expand Up @@ -21140,12 +21185,6 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,
return ir_const_void(ira, &instruction->base);
}

static IrInstruction *ir_analyze_instruction_result_error_union_payload(IrAnalyze *ira,
IrInstructionResultErrorUnionPayload *instruction)
{
zig_panic("TODO");
}

static IrInstruction *ir_analyze_instruction_result_return(IrAnalyze *ira, IrInstructionResultReturn *instruction) {
ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
if (fn == nullptr) {
Expand Down Expand Up @@ -21214,6 +21253,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdDeclVarGen:
case IrInstructionIdAllocaGen:
case IrInstructionIdResultOptionalPayload:
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultErrorUnionCode:
zig_unreachable();

case IrInstructionIdReturn:
Expand Down Expand Up @@ -21480,8 +21521,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
case IrInstructionIdCheckRuntimeScope:
return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
case IrInstructionIdResultErrorUnionPayload:
return ir_analyze_instruction_result_error_union_payload(ira, (IrInstructionResultErrorUnionPayload *)instruction);
case IrInstructionIdResultReturn:
return ir_analyze_instruction_result_return(ira, (IrInstructionResultReturn *)instruction);
case IrInstructionIdResultParam:
Expand Down Expand Up @@ -21718,6 +21757,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdEnumToInt:
case IrInstructionIdResultOptionalPayload:
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultErrorUnionCode:
case IrInstructionIdResultReturn:
case IrInstructionIdResultParam:
case IrInstructionIdResultPtrCast:
Expand Down
9 changes: 9 additions & 0 deletions src/ir_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,12 @@ static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResul
fprintf(irp->f, ")");
}

static void ir_print_result_error_union_code(IrPrint *irp, IrInstructionResultErrorUnionCode *instruction) {
fprintf(irp->f, "ResultErrorUnionCode(");
ir_print_other_instruction(irp, instruction->prev_result_loc);
fprintf(irp->f, ")");
}

static void ir_print_result_return(IrPrint *irp, IrInstructionResultReturn *instruction) {
fprintf(irp->f, "ResultReturn");
}
Expand Down Expand Up @@ -1815,6 +1821,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdResultErrorUnionPayload:
ir_print_result_error_union_payload(irp, (IrInstructionResultErrorUnionPayload *)instruction);
break;
case IrInstructionIdResultErrorUnionCode:
ir_print_result_error_union_code(irp, (IrInstructionResultErrorUnionCode *)instruction);
break;
case IrInstructionIdResultReturn:
ir_print_result_return(irp, (IrInstructionResultReturn *)instruction);
break;
Expand Down

0 comments on commit 5106eac

Please sign in to comment.