diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-17 16:06:48 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-17 16:16:17 -0500 |
| commit | 12fcbecbf8a1c8496354b909e0de2a69600115a9 (patch) | |
| tree | 4c625d36661db5860196763f8d952753f12d1fd4 /src | |
| parent | 3a3cc7bf76eab3ef239991e686c114baeaf4672e (diff) | |
| download | zig-12fcbecbf8a1c8496354b909e0de2a69600115a9.tar.gz zig-12fcbecbf8a1c8496354b909e0de2a69600115a9.zip | |
IR: add more instructions
* MaybeWrap
* TestErr
* UnwrapErrCode
* UnwrapErrPayload
* ErrUnionTypeChild
* ErrWrapCode
* ErrWrapPayload
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 84 | ||||
| -rw-r--r-- | src/ast_render.cpp | 12 | ||||
| -rw-r--r-- | src/codegen.cpp | 288 | ||||
| -rw-r--r-- | src/eval.cpp | 17 | ||||
| -rw-r--r-- | src/ir.cpp | 890 | ||||
| -rw-r--r-- | src/ir_print.cpp | 74 |
6 files changed, 845 insertions, 520 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 40d6b73589..14a0cbcc53 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -115,14 +115,26 @@ enum ConstValSpecial { ConstValSpecialZeroes, }; +enum RuntimeHintErrorUnion { + RuntimeHintErrorUnionUnknown, + RuntimeHintErrorUnionError, + RuntimeHintErrorUnionNonError, +}; + +enum RuntimeHintMaybe { + RuntimeHintMaybeUnknown, + RuntimeHintMaybeNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known. + RuntimeHintMaybeNonNull, +}; + struct ConstExprValue { ConstValSpecial special; bool depends_on_compile_var; LLVMValueRef llvm_value; LLVMValueRef llvm_global; - // populated if val_type == ConstValTypeOk union { + // populated if special == ConstValSpecialStatic BigNum x_bignum; bool x_bool; FnTableEntry *x_fn; @@ -137,6 +149,10 @@ struct ConstExprValue { ConstPtrValue x_ptr; ImportTableEntry *x_import; Scope *x_block; + + // populated if special == ConstValSpecialRuntime + RuntimeHintErrorUnion rh_error_union; + RuntimeHintMaybe rh_maybe; } data; }; @@ -412,10 +428,6 @@ enum CastOp { CastOpIntToPtr, CastOpWidenOrShorten, CastOpToUnknownSizeArray, - CastOpMaybeWrap, - CastOpNullToMaybe, - CastOpErrorWrap, - CastOpPureErrorWrap, CastOpPointerReinterpret, CastOpErrToInt, CastOpIntToFloat, @@ -1394,6 +1406,7 @@ enum IrInstructionId { IrInstructionIdSizeOf, IrInstructionIdTestNull, IrInstructionIdUnwrapMaybe, + IrInstructionIdMaybeWrap, IrInstructionIdEnumTag, IrInstructionIdClz, IrInstructionIdCtz, @@ -1426,6 +1439,12 @@ enum IrInstructionId { IrInstructionIdFrameAddress, IrInstructionIdAlignOf, IrInstructionIdOverflowOp, + IrInstructionIdTestErr, + IrInstructionIdUnwrapErrCode, + IrInstructionIdUnwrapErrPayload, + IrInstructionIdErrUnionTypeChild, + IrInstructionIdErrWrapCode, + IrInstructionIdErrWrapPayload, }; struct IrInstruction { @@ -1439,7 +1458,6 @@ struct IrInstruction { // if ref_count is zero, instruction can be omitted in codegen size_t ref_count; IrInstruction *other; - ReturnKnowledge return_knowledge; }; struct IrInstructionCondBr { @@ -1504,10 +1522,6 @@ enum IrUnOp { IrUnOpDereference, IrUnOpError, IrUnOpMaybe, - IrUnOpUnwrapError, - IrUnOpUnwrapMaybe, - IrUnOpErrorReturn, - IrUnOpMaybeReturn, }; struct IrInstructionUnOp { @@ -2004,6 +2018,53 @@ struct IrInstructionAlignOf { IrInstruction *type_value; }; +// returns true if error, returns false if not error +struct IrInstructionTestErr { + IrInstruction base; + + IrInstruction *value; +}; + +struct IrInstructionUnwrapErrCode { + IrInstruction base; + + IrInstruction *value; +}; + +struct IrInstructionUnwrapErrPayload { + IrInstruction base; + + IrInstruction *value; + bool safety_check_on; +}; + +struct IrInstructionErrUnionTypeChild { + IrInstruction base; + + IrInstruction *type_value; +}; + +struct IrInstructionMaybeWrap { + IrInstruction base; + + IrInstruction *value; + LLVMValueRef tmp_ptr; +}; + +struct IrInstructionErrWrapPayload { + IrInstruction base; + + IrInstruction *value; + LLVMValueRef tmp_ptr; +}; + +struct IrInstructionErrWrapCode { + IrInstruction base; + + IrInstruction *value; + LLVMValueRef tmp_ptr; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, @@ -2019,4 +2080,7 @@ static const size_t maybe_null_index = 1; static const size_t enum_gen_tag_index = 0; static const size_t enum_gen_union_index = 1; +static const size_t err_union_err_index = 0; +static const size_t err_union_payload_index = 1; + #endif diff --git a/src/ast_render.cpp b/src/ast_render.cpp index e0a7bf6f31..1134d6674e 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -862,10 +862,20 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, "const"); break; } + case NodeTypeUnwrapErrorExpr: + { + render_node_ungrouped(ar, node->data.unwrap_err_expr.op1); + fprintf(ar->f, " %%%% "); + if (node->data.unwrap_err_expr.symbol) { + Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol; + fprintf(ar->f, "|%s| ", buf_ptr(var_name)); + } + render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); + break; + } case NodeTypeFnDecl: case NodeTypeParamDecl: case NodeTypeErrorValueDecl: - case NodeTypeUnwrapErrorExpr: case NodeTypeStructField: case NodeTypeUse: case NodeTypeZeroesLiteral: diff --git a/src/codegen.cpp b/src/codegen.cpp index 78a07ed3d1..2f540b63aa 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -969,63 +969,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, } else { zig_panic("TODO"); } - case CastOpMaybeWrap: - { - assert(cast_instruction->tmp_ptr); - assert(wanted_type->id == TypeTableEntryIdMaybe); - assert(actual_type); - - TypeTableEntry *child_type = wanted_type->data.maybe.child_type; - - if (child_type->id == TypeTableEntryIdPointer || - child_type->id == TypeTableEntryIdFn) - { - return expr_val; - } else { - LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, ""); - gen_assign_raw(g, cast_instruction->base.source_node, - val_ptr, expr_val, child_type, actual_type); - - LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, ""); - LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); - } - - return cast_instruction->tmp_ptr; - } - case CastOpNullToMaybe: - // handled by constant expression evaluator - zig_unreachable(); - case CastOpErrorWrap: - { - assert(wanted_type->id == TypeTableEntryIdErrorUnion); - TypeTableEntry *child_type = wanted_type->data.error.child_type; - LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref); - - if (!type_has_bits(child_type)) { - return ok_err_val; - } else { - assert(cast_instruction->tmp_ptr); - assert(wanted_type->id == TypeTableEntryIdErrorUnion); - assert(actual_type); - - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, ""); - LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr); - - LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, ""); - gen_assign_raw(g, cast_instruction->base.source_node, - payload_ptr, expr_val, child_type, actual_type); - - return cast_instruction->tmp_ptr; - } - } - case CastOpPureErrorWrap: - assert(wanted_type->id == TypeTableEntryIdErrorUnion); - - if (!type_has_bits(wanted_type->data.error.child_type)) { - return expr_val; - } else { - zig_panic("TODO"); - } case CastOpPtrToInt: return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); case CastOpIntToPtr: @@ -1257,78 +1200,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst { zig_panic("TODO codegen PrefixOpMaybe"); } - case IrUnOpUnwrapError: - { - assert(expr_type->id == TypeTableEntryIdErrorUnion); - TypeTableEntry *child_type = expr_type->data.error.child_type; - - if (ir_want_debug_safety(g, &un_op_instruction->base)) { - LLVMValueRef err_val; - if (type_has_bits(child_type)) { - LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr, 0, ""); - err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); - } else { - err_val = expr; - } - LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); - LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); - LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk"); - LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); - - LLVMPositionBuilderAtEnd(g->builder, err_block); - gen_debug_safety_crash(g); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - if (type_has_bits(child_type)) { - LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr, 1, ""); - return get_handle_value(g, child_val_ptr, child_type); - } else { - return nullptr; - } - } - case IrUnOpUnwrapMaybe: - { - assert(expr_type->id == TypeTableEntryIdMaybe); - TypeTableEntry *child_type = expr_type->data.maybe.child_type; - - if (ir_want_debug_safety(g, &un_op_instruction->base)) { - LLVMValueRef cond_val; - if (child_type->id == TypeTableEntryIdPointer || - child_type->id == TypeTableEntryIdFn) - { - cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, expr, - LLVMConstNull(child_type->type_ref), ""); - } else { - LLVMValueRef maybe_null_ptr = LLVMBuildStructGEP(g->builder, expr, 1, ""); - cond_val = LLVMBuildLoad(g->builder, maybe_null_ptr, ""); - } - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk"); - LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeNull"); - LLVMBuildCondBr(g->builder, cond_val, ok_block, null_block); - - LLVMPositionBuilderAtEnd(g->builder, null_block); - gen_debug_safety_crash(g); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - - if (child_type->id == TypeTableEntryIdPointer || - child_type->id == TypeTableEntryIdFn) - { - return expr; - } else { - LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, expr, 0, ""); - return get_handle_value(g, maybe_field_ptr, child_type); - } - } - case IrUnOpErrorReturn: - case IrUnOpMaybeReturn: - zig_panic("TODO codegen more un ops"); } zig_unreachable(); @@ -2132,6 +2003,143 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, return overflow_bit; } +static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) { + TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry); + TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type); + TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type); + LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); + LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type); + + LLVMValueRef err_val; + if (type_has_bits(child_type)) { + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); + err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); + } else { + err_val = err_union_handle; + } + + LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); + return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); +} + +static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { + TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry); + TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type); + TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type); + LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); + LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type); + + if (type_has_bits(child_type)) { + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); + return LLVMBuildLoad(g->builder, err_val_ptr, ""); + } else { + return err_union_handle; + } +} + +static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { + TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry); + TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type); + TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type); + LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); + LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type); + + if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) { + LLVMValueRef err_val; + if (type_has_bits(child_type)) { + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); + err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); + } else { + err_val = err_union_handle; + } + LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); + LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); + LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk"); + LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); + + LLVMPositionBuilderAtEnd(g->builder, err_block); + gen_debug_safety_crash(g); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + } + + if (type_has_bits(child_type)) { + return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); + } else { + return nullptr; + } +} + +static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) { + TypeTableEntry *wanted_type = instruction->base.type_entry; + + assert(wanted_type->id == TypeTableEntryIdMaybe); + + TypeTableEntry *child_type = wanted_type->data.maybe.child_type; + + LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); + if (child_type->id == TypeTableEntryIdPointer || + child_type->id == TypeTableEntryIdFn) + { + return payload_val; + } + + assert(instruction->tmp_ptr); + + LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); + gen_assign_raw(g, instruction->base.source_node, val_ptr, payload_val, child_type, instruction->value->type_entry); + + LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); + LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); + + return instruction->tmp_ptr; +} + +static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) { + TypeTableEntry *wanted_type = instruction->base.type_entry; + + assert(wanted_type->id == TypeTableEntryIdErrorUnion); + + TypeTableEntry *child_type = wanted_type->data.error.child_type; + LLVMValueRef err_val = ir_llvm_value(g, instruction->value); + + if (!type_has_bits(child_type)) + return err_val; + + assert(instruction->tmp_ptr); + + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMBuildStore(g->builder, err_val, err_tag_ptr); + + return instruction->tmp_ptr; +} + +static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) { + TypeTableEntry *wanted_type = instruction->base.type_entry; + + assert(wanted_type->id == TypeTableEntryIdErrorUnion); + + TypeTableEntry *child_type = wanted_type->data.error.child_type; + + LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref); + + if (!type_has_bits(child_type)) + return ok_err_val; + + assert(instruction->tmp_ptr); + + LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); + + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr); + + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); + gen_assign_raw(g, instruction->base.source_node, payload_ptr, payload_val, child_type, instruction->value->type_entry); + + return instruction->tmp_ptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -2175,6 +2183,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdIntType: case IrInstructionIdMemberCount: case IrInstructionIdAlignOf: + case IrInstructionIdErrUnionTypeChild: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -2250,6 +2259,18 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction); case IrInstructionIdOverflowOp: return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction); + case IrInstructionIdTestErr: + return ir_render_test_err(g, executable, (IrInstructionTestErr *)instruction); + case IrInstructionIdUnwrapErrCode: + return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction); + case IrInstructionIdUnwrapErrPayload: + return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction); + case IrInstructionIdMaybeWrap: + return ir_render_maybe_wrap(g, executable, (IrInstructionMaybeWrap *)instruction); + case IrInstructionIdErrWrapCode: + return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction); + case IrInstructionIdErrWrapPayload: + return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); case IrInstructionIdSwitchVar: case IrInstructionIdContainerInitList: case IrInstructionIdStructInit: @@ -2835,6 +2856,15 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdMaybeWrap) { + IrInstructionMaybeWrap *maybe_wrap_instruction = (IrInstructionMaybeWrap *)instruction; + slot = &maybe_wrap_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdErrWrapPayload) { + IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction; + slot = &err_wrap_payload_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdErrWrapCode) { + IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; + slot = &err_wrap_code_instruction->tmp_ptr; } else { zig_unreachable(); } diff --git a/src/eval.cpp b/src/eval.cpp index 9adb0c0cf9..c1a8bc604b 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -342,23 +342,6 @@ void eval_const_expr_implicit_cast(CastOp cast_op, const_val->special = ConstValSpecialStatic; break; } - case CastOpMaybeWrap: - const_val->data.x_maybe = other_val; - const_val->special = ConstValSpecialStatic; - break; - case CastOpNullToMaybe: - const_val->data.x_maybe = nullptr; - const_val->special = ConstValSpecialStatic; - break; - case CastOpErrorWrap: - const_val->data.x_err_union.err = nullptr; - const_val->data.x_err_union.payload = other_val; - const_val->special = ConstValSpecialStatic; - break; - case CastOpPureErrorWrap: - const_val->data.x_err_union.err = other_val->data.x_pure_err; - const_val->special = ConstValSpecialStatic; - break; case CastOpErrToInt: { uint64_t value; diff --git a/src/ir.cpp b/src/ir.cpp index a541c3243e..8b3ef36bd8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -93,6 +93,10 @@ static Buf *exec_c_import_buf(IrExecutable *exec) { return exec->c_import_buf; } +static bool instr_is_comptime(IrInstruction *instruction) { + return instruction->static_value.special != ConstValSpecialRuntime; +} + static void ir_link_new_instruction(IrInstruction *new_instruction, IrInstruction *old_instruction) { new_instruction->other = old_instruction; old_instruction->other = new_instruction; @@ -411,6 +415,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) { return IrInstructionIdOverflowOp; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) { + return IrInstructionIdTestErr; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) { + return IrInstructionIdUnwrapErrCode; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrPayload *) { + return IrInstructionIdUnwrapErrPayload; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionErrUnionTypeChild *) { + return IrInstructionIdErrUnionTypeChild; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionMaybeWrap *) { + return IrInstructionIdMaybeWrap; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapPayload *) { + return IrInstructionIdErrWrapPayload; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapCode *) { + return IrInstructionIdErrWrapCode; +} + template<typename T> static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -1037,8 +1069,11 @@ static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionPtrTypeChild *instruction = ir_build_instruction<IrInstructionPtrTypeChild>(irb, scope, source_node); +static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionPtrTypeChild *instruction = ir_build_instruction<IrInstructionPtrTypeChild>( + irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -1198,6 +1233,33 @@ static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction * return new_instruction; } +static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionMaybeWrap *instruction = ir_build_instruction<IrInstructionMaybeWrap>(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value); + + return &instruction->base; +} + +static IrInstruction *ir_build_err_wrap_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionErrWrapPayload *instruction = ir_build_instruction<IrInstructionErrWrapPayload>(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value); + + return &instruction->base; +} + +static IrInstruction *ir_build_err_wrap_code(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionErrWrapCode *instruction = ir_build_instruction<IrInstructionErrWrapCode>(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value); + + return &instruction->base; +} + static IrInstruction *ir_build_clz(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { IrInstructionClz *instruction = ir_build_instruction<IrInstructionClz>(irb, scope, source_node); instruction->value = value; @@ -1709,6 +1771,76 @@ static IrInstruction *ir_build_alignof(IrBuilder *irb, Scope *scope, AstNode *so return &instruction->base; } +static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionTestErr *instruction = ir_build_instruction<IrInstructionTestErr>(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value); + + return &instruction->base; +} + +static IrInstruction *ir_build_test_err_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) { + IrInstruction *new_instruction = ir_build_test_err(irb, old_instruction->scope, old_instruction->source_node, + value); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + +static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionUnwrapErrCode *instruction = ir_build_instruction<IrInstructionUnwrapErrCode>(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value); + + return &instruction->base; +} + +static IrInstruction *ir_build_unwrap_err_code_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *value) +{ + IrInstruction *new_instruction = ir_build_unwrap_err_code(irb, old_instruction->scope, + old_instruction->source_node, value); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + +static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, bool safety_check_on) +{ + IrInstructionUnwrapErrPayload *instruction = ir_build_instruction<IrInstructionUnwrapErrPayload>(irb, scope, source_node); + instruction->value = value; + instruction->safety_check_on = safety_check_on; + + ir_ref_instruction(value); + + return &instruction->base; +} + +static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *value, bool safety_check_on) +{ + IrInstruction *new_instruction = ir_build_unwrap_err_payload(irb, old_instruction->scope, + old_instruction->source_node, value, safety_check_on); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + +static IrInstruction *ir_build_err_union_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *type_value) +{ + IrInstructionErrUnionTypeChild *instruction = ir_build_instruction<IrInstructionErrUnionTypeChild>(irb, scope, source_node); + instruction->type_value = type_value; + + ir_ref_instruction(type_value); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -1799,7 +1931,29 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, return ir_build_return(irb, scope, node, return_value); } case ReturnKindError: - zig_panic("TODO gen IR for %%return"); + { + assert(expr_node); + IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); + if (err_union_ptr == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_ptr); + + IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "ErrRetReturn"); + IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "ErrRetContinue"); + ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_inline); + + ir_set_cursor_at_end(irb, return_block); + ir_gen_defers_for_block(irb, scope, outer_scope, true, false); + IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); + ir_build_return(irb, scope, node, err_val); + + ir_set_cursor_at_end(irb, continue_block); + IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false); + if (lval != LValPurposeNone) + return unwrapped_ptr; + else + return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + } case ReturnKindMaybe: { assert(expr_node); @@ -2798,13 +2952,33 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValPurposeNone); } -static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { - AstNode *expr = node->data.prefix_op_expr.primary_expr; - IrInstruction *value = ir_gen_node_extra(irb, expr, scope, LValPurposeAddressOf); - if (value == irb->codegen->invalid_instruction) - return value; +static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { + assert(node->type == NodeTypePrefixOpExpr); + AstNode *expr_node = node->data.prefix_op_expr.primary_expr; + + IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); + if (err_union_ptr == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, true); + if (payload_ptr == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; - IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, value, true); + if (lval == LValPurposeNone) + return ir_build_load_ptr(irb, scope, node, payload_ptr); + else + return payload_ptr; +} + +static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { + assert(node->type == NodeTypePrefixOpExpr); + AstNode *expr_node = node->data.prefix_op_expr.primary_expr; + + IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); + if (maybe_ptr == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true); if (lval == LValPurposeNone) return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); else @@ -2860,9 +3034,9 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod case PrefixOpError: return ir_gen_prefix_op_id(irb, scope, node, IrUnOpError); case PrefixOpUnwrapError: - return ir_gen_prefix_op_id(irb, scope, node, IrUnOpUnwrapError); + return ir_gen_err_assert_ok(irb, scope, node, lval); case PrefixOpUnwrapMaybe: - return ir_gen_prefix_op_unwrap_maybe(irb, scope, node, lval); + return ir_gen_maybe_assert_ok(irb, scope, node, lval); } zig_unreachable(); } @@ -3626,6 +3800,66 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, slice_expr->is_const); } +static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeUnwrapErrorExpr); + + AstNode *op1_node = node->data.unwrap_err_expr.op1; + AstNode *op2_node = node->data.unwrap_err_expr.op2; + AstNode *var_node = node->data.unwrap_err_expr.symbol; + + bool is_inline = ir_should_inline(irb); + + IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPurposeAddressOf); + if (err_union_ptr == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_ptr); + + IrBasicBlock *ok_block = ir_build_basic_block(irb, parent_scope, "UnwrapErrOk"); + IrBasicBlock *err_block = ir_build_basic_block(irb, parent_scope, "UnwrapErrError"); + IrBasicBlock *end_block = ir_build_basic_block(irb, parent_scope, "UnwrapErrEnd"); + ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_inline); + + ir_set_cursor_at_end(irb, err_block); + Scope *err_scope; + if (var_node) { + assert(var_node->type == NodeTypeSymbol); + IrInstruction *err_union_ptr_type = ir_build_typeof(irb, parent_scope, var_node, err_union_ptr); + IrInstruction *err_union_type = ir_build_ptr_type_child(irb, parent_scope, var_node, err_union_ptr_type); + IrInstruction *var_type = ir_build_err_union_type_child(irb, parent_scope, var_node, err_union_type); + Buf *var_name = var_node->data.symbol_expr.symbol; + bool is_const = true; + bool is_shadowable = false; + VariableTableEntry *var = ir_create_var(irb, node, parent_scope, var_name, + is_const, is_const, is_shadowable, is_inline); + err_scope = var->child_scope; + IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); + ir_build_var_decl(irb, err_scope, var_node, var, var_type, err_val); + } else { + err_scope = parent_scope; + } + IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope); + if (err_result == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + IrBasicBlock *after_err_block = irb->current_basic_block; + ir_build_br(irb, err_scope, node, end_block, is_inline); + + ir_set_cursor_at_end(irb, ok_block); + IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false); + IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); + IrBasicBlock *after_ok_block = irb->current_basic_block; + ir_build_br(irb, parent_scope, node, end_block, is_inline); + + ir_set_cursor_at_end(irb, end_block); + IrInstruction **incoming_values = allocate<IrInstruction *>(2); + incoming_values[0] = err_result; + incoming_values[1] = unwrapped_payload; + IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); + incoming_blocks[0] = after_err_block; + incoming_blocks[1] = after_ok_block; + return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); +} + static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LValPurpose lval) { @@ -3703,6 +3937,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSliceExpr: return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); case NodeTypeUnwrapErrorExpr: + return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval); case NodeTypeZeroesLiteral: case NodeTypeVarLiteral: case NodeTypeFnProto: @@ -4279,11 +4514,20 @@ static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *ins } static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) { - if (value->static_value.special != ConstValSpecialStatic) { - ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression")); - return nullptr; + switch (value->static_value.special) { + case ConstValSpecialStatic: + return &value->static_value; + case ConstValSpecialRuntime: + ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression")); + return nullptr; + case ConstValSpecialUndef: + ir_add_error(ira, value, buf_sprintf("use of undefined value")); + return nullptr; + case ConstValSpecialZeroes: + ir_add_error(ira, value, buf_sprintf("zeroes is deprecated")); + return nullptr; } - return &value->static_value; + zig_unreachable(); } IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, @@ -4375,6 +4619,95 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { return const_val->data.x_fn; } +static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { + assert(wanted_type->id == TypeTableEntryIdMaybe); + + if (instr_is_comptime(value)) { + ConstExprValue *val = ir_resolve_const(ira, value); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec, + source_instr->scope, source_instr->source_node); + const_instruction->base.type_entry = wanted_type; + const_instruction->base.static_value.special = ConstValSpecialStatic; + const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var; + const_instruction->base.static_value.data.x_maybe = &value->static_value; + return &const_instruction->base; + } + + IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value); + result->type_entry = wanted_type; + result->static_value.data.rh_maybe = RuntimeHintMaybeNonNull; + ir_add_alloca(ira, result, wanted_type); + return result; +} + +static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { + assert(wanted_type->id == TypeTableEntryIdErrorUnion); + + if (instr_is_comptime(value)) { + ConstExprValue *val = ir_resolve_const(ira, value); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec, + source_instr->scope, source_instr->source_node); + const_instruction->base.type_entry = wanted_type; + const_instruction->base.static_value.special = ConstValSpecialStatic; + const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var; + const_instruction->base.static_value.data.x_err_union.err = nullptr; + const_instruction->base.static_value.data.x_err_union.payload = val; + return &const_instruction->base; + } + + IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, source_instr->source_node, value); + result->type_entry = wanted_type; + result->static_value.data.rh_error_union = RuntimeHintErrorUnionNonError; + ir_add_alloca(ira, result, wanted_type); + return result; +} + +static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { + assert(wanted_type->id == TypeTableEntryIdErrorUnion); + + if (instr_is_comptime(value)) { + ConstExprValue *val = ir_resolve_const(ira, value); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec, + source_instr->scope, source_instr->source_node); + const_instruction->base.type_entry = wanted_type; + const_instruction->base.static_value.special = ConstValSpecialStatic; + const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var; + const_instruction->base.static_value.data.x_err_union.err = val->data.x_pure_err; + const_instruction->base.static_value.data.x_err_union.payload = nullptr; + return &const_instruction->base; + } + + IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, value); + result->type_entry = wanted_type; + result->static_value.data.rh_error_union = RuntimeHintErrorUnionError; + ir_add_alloca(ira, result, wanted_type); + return result; +} + +static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { + assert(wanted_type->id == TypeTableEntryIdMaybe); + assert(instr_is_comptime(value)); + + ConstExprValue *val = ir_resolve_const(ira, value); + assert(val); + + IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec, source_instr->scope, source_instr->source_node); + const_instruction->base.type_entry = wanted_type; + const_instruction->base.static_value.special = ConstValSpecialStatic; + const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var; + const_instruction->base.static_value.data.x_maybe = nullptr; + return &const_instruction->base; +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, TypeTableEntry *wanted_type, IrInstruction *value) { @@ -4503,18 +4836,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from child type of maybe type to maybe type if (wanted_type->id == TypeTableEntryIdMaybe) { if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, - CastOpMaybeWrap, true); - cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull; - return cast_instruction; + return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); } else if (actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, - CastOpMaybeWrap, true); - cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull; - return cast_instruction; + return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); } else { return ira->codegen->invalid_instruction; } @@ -4525,27 +4852,18 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdNullLit) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, - CastOpNullToMaybe, true); - cast_instruction->return_knowledge = ReturnKnowledgeKnownNull; - return cast_instruction; + return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type); } // explicit cast from child type of error type to error type if (wanted_type->id == TypeTableEntryIdErrorUnion) { if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, - CastOpErrorWrap, true); - cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError; - return cast_instruction; + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); } else if (actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, - CastOpErrorWrap, true); - cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError; - return cast_instruction; + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); } else { return ira->codegen->invalid_instruction; } @@ -4556,10 +4874,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdPureError) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, - CastOpPureErrorWrap, false); - cast_instruction->return_knowledge = ReturnKnowledgeKnownError; - return cast_instruction; + return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); } // explicit cast from number literal to another type @@ -5997,33 +6312,6 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op zig_unreachable(); } -static TypeTableEntry *ir_analyze_unwrap_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { - IrInstruction *value = un_op_instruction->value->other; - TypeTableEntry *type_entry = value->type_entry; - if (type_entry->id == TypeTableEntryIdInvalid) { - return type_entry; - } else if (type_entry->id == TypeTableEntryIdMaybe) { - if (value->static_value.special != ConstValSpecialRuntime) { - bool depends_on_compile_var = value->static_value.depends_on_compile_var; - ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, depends_on_compile_var); - ConstExprValue *child_val = value->static_value.data.x_maybe; - if (!child_val) { - ir_add_error(ira, &un_op_instruction->base, - buf_sprintf("unable to unwrap null")); - return ira->codegen->builtin_types.entry_invalid; - } - *out_val = *child_val; - return type_entry->data.maybe.child_type; - } - ir_build_un_op_from(&ira->new_irb, &un_op_instruction->base, IrUnOpUnwrapMaybe, value); - return type_entry->data.maybe.child_type; - } else { - add_node_error(ira->codegen, un_op_instruction->base.source_node, - buf_sprintf("expected maybe type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->builtin_types.entry_invalid; - } -} - static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { IrInstruction *value = un_op_instruction->value->other; TypeTableEntry *expr_type = value->type_entry; @@ -6099,27 +6387,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio return ir_analyze_maybe(ira, un_op_instruction); case IrUnOpError: return ir_analyze_unary_prefix_op_err(ira, un_op_instruction); - case IrUnOpUnwrapError: - zig_panic("TODO analyze PrefixOpUnwrapError"); - //{ - // TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node); - - // if (type_entry->id == TypeTableEntryIdInvalid) { - // return type_entry; - // } else if (type_entry->id == TypeTableEntryIdErrorUnion) { - // return type_entry->data.error.child_type; - // } else { - // add_node_error(g, *expr_node, - // buf_sprintf("expected error type, found '%s'", buf_ptr(&type_entry->name))); - // return g->builtin_types.entry_invalid; - // } - //} - case IrUnOpUnwrapMaybe: - return ir_analyze_unwrap_maybe(ira, un_op_instruction); - case IrUnOpErrorReturn: - zig_panic("TODO analyze IrUnOpErrorReturn"); - case IrUnOpMaybeReturn: - zig_panic("TODO analyze IrUnOpMaybeReturn"); } zig_unreachable(); } @@ -6835,6 +7102,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, if (type_entry->id == TypeTableEntryIdInvalid) return type_entry; + // TODO handle typedefs if (type_entry->id != TypeTableEntryIdPointer) { add_node_error(ira->codegen, ptr_type_child_instruction->base.source_node, buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); @@ -7243,6 +7511,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, assert(ptr_type->id == TypeTableEntryIdPointer); TypeTableEntry *type_entry = ptr_type->data.pointer.child_type; + // TODO handle typedef if (type_entry->id == TypeTableEntryIdInvalid) { return ira->codegen->builtin_types.entry_invalid; } else if (type_entry->id != TypeTableEntryIdMaybe) { @@ -7253,9 +7522,12 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, TypeTableEntry *child_type = type_entry->data.maybe.child_type; TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false); - if (value->static_value.special != ConstValSpecialRuntime) { - ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr; - assert(value->static_value.data.x_ptr.index == SIZE_MAX); + if (instr_is_comptime(value)) { + ConstExprValue *val = ir_resolve_const(ira, value); + if (!val) + return ira->codegen->builtin_types.entry_invalid; + ConstExprValue *maybe_val = val->data.x_ptr.base_ptr; + assert(val->data.x_ptr.index == SIZE_MAX); if (maybe_val->special != ConstValSpecialRuntime) { if (!maybe_val->data.x_maybe) { @@ -8837,6 +9109,161 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst return ira->codegen->builtin_types.entry_bool; } +static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) { + IrInstruction *value = instruction->value->other; + if (value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *ptr_type = value->type_entry; + + // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. + assert(ptr_type->id == TypeTableEntryIdPointer); + + TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type; + TypeTableEntry *canon_type = get_underlying_type(non_canon_type); + if (canon_type->id == TypeTableEntryIdInvalid) { + return ira->codegen->builtin_types.entry_invalid; + } else if (canon_type->id == TypeTableEntryIdErrorUnion) { + if (instr_is_comptime(value)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, value); + if (!ptr_val) + return ira->codegen->builtin_types.entry_invalid; + ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr; + assert(ptr_val->data.x_ptr.index == SIZE_MAX); + + if (err_union_val->special != ConstValSpecialRuntime) { + bool depends_on_compile_var = ptr_val->depends_on_compile_var || err_union_val->depends_on_compile_var; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); + out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr); + return ira->codegen->builtin_types.entry_bool; + } + } + + ir_build_test_err_from(&ira->new_irb, &instruction->base, value); + return ira->codegen->builtin_types.entry_bool; + } else { + ir_add_error(ira, value, + buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name))); + // TODO if this is a typedecl, add error note showing the declaration of the type decl + return ira->codegen->builtin_types.entry_invalid; + } +} + +static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, + IrInstructionUnwrapErrCode *instruction) +{ + IrInstruction *value = instruction->value->other; + if (value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + TypeTableEntry *ptr_type = value->type_entry; + + // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. + assert(ptr_type->id == TypeTableEntryIdPointer); + + TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type; + TypeTableEntry *canon_type = get_underlying_type(non_canon_type); + if (canon_type->id == TypeTableEntryIdInvalid) { + return ira->codegen->builtin_types.entry_invalid; + } else if (canon_type->id == TypeTableEntryIdErrorUnion) { + if (instr_is_comptime(value)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, value); + if (!ptr_val) + return ira->codegen->builtin_types.entry_invalid; + ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr; + assert(ptr_val->data.x_ptr.index == SIZE_MAX); + if (err_union_val->special != ConstValSpecialRuntime) { + ErrorTableEntry *err = err_union_val->data.x_err_union.err; + assert(err); + + bool depends_on_compile_var = ptr_val->depends_on_compile_var || err_union_val->depends_on_compile_var; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); + out_val->data.x_pure_err = err; + return ira->codegen->builtin_types.entry_pure_error; + } + } + + ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value); + return ira->codegen->builtin_types.entry_pure_error; + } else { + ir_add_error(ira, value, + buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name))); + // TODO if this is a typedecl, add error note showing the declaration of the type decl + return ira->codegen->builtin_types.entry_invalid; + } +} + +static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, + IrInstructionUnwrapErrPayload *instruction) +{ + IrInstruction *value = instruction->value->other; + if (value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + TypeTableEntry *ptr_type = value->type_entry; + + // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. + assert(ptr_type->id == TypeTableEntryIdPointer); + + TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type; + TypeTableEntry *canon_type = get_underlying_type(non_canon_type); + if (canon_type->id == TypeTableEntryIdInvalid) { + return ira->codegen->builtin_types.entry_invalid; + } else if (canon_type->id == TypeTableEntryIdErrorUnion) { + TypeTableEntry *child_type = canon_type->data.error.child_type; + TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false); + if (instr_is_comptime(value)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, value); + if (!ptr_val) + return ira->codegen->builtin_types.entry_invalid; + ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr; + assert(ptr_val->data.x_ptr.index == SIZE_MAX); + if (err_union_val->special != ConstValSpecialRuntime) { + ErrorTableEntry *err = err_union_val->data.x_err_union.err; + if (err != nullptr) { + ir_add_error(ira, &instruction->base, + buf_sprintf("unable to unwrap error '%s'", buf_ptr(&err->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + bool depends_on_compile_var = ptr_val->depends_on_compile_var || err_union_val->depends_on_compile_var; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); + out_val->data.x_ptr.base_ptr = err_union_val->data.x_err_union.payload; + out_val->data.x_ptr.index = SIZE_MAX; + return result_type; + } + } + + ir_build_unwrap_err_payload_from(&ira->new_irb, &instruction->base, value, instruction->safety_check_on); + return result_type; + } else { + ir_add_error(ira, value, + buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name))); + // TODO if this is a typedecl, add error note showing the declaration of the type decl + return ira->codegen->builtin_types.entry_invalid; + } + +} + +static TypeTableEntry *ir_analyze_instruction_err_union_type_child(IrAnalyze *ira, + IrInstructionErrUnionTypeChild *instruction) +{ + IrInstruction *type_value = instruction->type_value->other; + TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); + if (type_entry->id == TypeTableEntryIdInvalid) + return type_entry; + + // TODO handle typedefs + if (type_entry->id != TypeTableEntryIdErrorUnion) { + add_node_error(ira->codegen, instruction->base.source_node, + buf_sprintf("expected error type, found '%s'", buf_ptr(&type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, + type_value->static_value.depends_on_compile_var); + out_val->data.x_type = type_entry->data.error.child_type; + return ira->codegen->builtin_types.entry_type; +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -8971,6 +9398,17 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_alignof(ira, (IrInstructionAlignOf *)instruction); case IrInstructionIdOverflowOp: return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction); + case IrInstructionIdTestErr: + return ir_analyze_instruction_test_err(ira, (IrInstructionTestErr *)instruction); + case IrInstructionIdUnwrapErrCode: + return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction); + case IrInstructionIdUnwrapErrPayload: + return ir_analyze_instruction_unwrap_err_payload(ira, (IrInstructionUnwrapErrPayload *)instruction); + case IrInstructionIdErrUnionTypeChild: + return ir_analyze_instruction_err_union_type_child(ira, (IrInstructionErrUnionTypeChild *)instruction); + case IrInstructionIdMaybeWrap: + case IrInstructionIdErrWrapCode: + case IrInstructionIdErrWrapPayload: case IrInstructionIdCast: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: @@ -9122,6 +9560,13 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAlignOf: case IrInstructionIdReturnAddress: case IrInstructionIdFrameAddress: + case IrInstructionIdTestErr: + case IrInstructionIdUnwrapErrCode: + case IrInstructionIdUnwrapErrPayload: + case IrInstructionIdErrUnionTypeChild: + case IrInstructionIdMaybeWrap: + case IrInstructionIdErrWrapCode: + case IrInstructionIdErrWrapPayload: return false; case IrInstructionIdAsm: { @@ -9131,268 +9576,3 @@ bool ir_has_side_effects(IrInstruction *instruction) { } zig_unreachable(); } - -// TODO port over all this commented out code into new IR way of doing things - -//static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// TypeTableEntry *expected_return_type = get_return_type(context); -// -// switch (node->data.return_expr.kind) { -// case ReturnKindError: -// { -// TypeTableEntry *expected_err_type; -// if (expected_type) { -// expected_err_type = get_error_type(g, expected_type); -// } else { -// expected_err_type = nullptr; -// } -// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_err_type, -// node->data.return_expr.expr); -// if (resolved_type->id == TypeTableEntryIdInvalid) { -// return resolved_type; -// } else if (resolved_type->id == TypeTableEntryIdErrorUnion) { -// if (expected_return_type->id != TypeTableEntryIdErrorUnion && -// expected_return_type->id != TypeTableEntryIdPureError) -// { -// ErrorMsg *msg = add_node_error(g, node, -// buf_sprintf("%%return statement in function with return type '%s'", -// buf_ptr(&expected_return_type->name))); -// AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type; -// add_error_note(g, msg, return_type_node, buf_sprintf("function return type here")); -// } -// -// return resolved_type->data.error.child_type; -// } else { -// add_node_error(g, node->data.return_expr.expr, -// buf_sprintf("expected error type, found '%s'", buf_ptr(&resolved_type->name))); -// return g->builtin_types.entry_invalid; -// } -// } -// } -// zig_unreachable(); -//} -//static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *import, -// BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node) -//{ -// AstNode *op1 = node->data.unwrap_err_expr.op1; -// AstNode *op2 = node->data.unwrap_err_expr.op2; -// AstNode *var_node = node->data.unwrap_err_expr.symbol; -// -// TypeTableEntry *lhs_type = analyze_expression(g, import, parent_context, nullptr, op1); -// if (lhs_type->id == TypeTableEntryIdInvalid) { -// return lhs_type; -// } else if (lhs_type->id == TypeTableEntryIdErrorUnion) { -// TypeTableEntry *child_type = lhs_type->data.error.child_type; -// BlockContext *child_context; -// if (var_node) { -// child_context = new_block_context(node, parent_context); -// var_node->block_context = child_context; -// Buf *var_name = var_node->data.symbol_expr.symbol; -// node->data.unwrap_err_expr.var = add_local_var(g, var_node, import, child_context, var_name, -// g->builtin_types.entry_pure_error, true, nullptr); -// } else { -// child_context = parent_context; -// } -// -// analyze_expression(g, import, child_context, child_type, op2); -// return child_type; -// } else { -// add_node_error(g, op1, -// buf_sprintf("expected error type, found '%s'", buf_ptr(&lhs_type->name))); -// return g->builtin_types.entry_invalid; -// } -//} -// -//static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) { -// if (type_entry->id == TypeTableEntryIdMetaType) { -// add_node_error(g, first_executing_node(source_node), buf_sprintf("expected expression, found type")); -// } else if (type_entry->id == TypeTableEntryIdErrorUnion) { -// add_node_error(g, first_executing_node(source_node), buf_sprintf("statement ignores error value")); -// } -//} -// -//static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type, -// AstNode *arg_node) -//{ -// assert(node->type == NodeTypeFieldAccessExpr); -// -// uint64_t value = node->data.field_access_expr.type_enum_field->value; -// LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref; -// LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false); -// -// if (enum_type->data.enumeration.gen_field_count == 0) { -// return tag_value; -// } else { -// TypeTableEntry *arg_node_type = nullptr; -// LLVMValueRef new_union_val = gen_expr(g, arg_node); -// if (arg_node) { -// arg_node_type = get_expr_type(arg_node); -// } else { -// arg_node_type = g->builtin_types.entry_void; -// } -// -// LLVMValueRef tmp_struct_ptr = node->data.field_access_expr.resolved_struct_val_expr.ptr; -// -// // populate the new tag value -// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); -// LLVMBuildStore(g->builder, tag_value, tag_field_ptr); -// -// if (arg_node_type->id != TypeTableEntryIdVoid) { -// // populate the union value -// TypeTableEntry *union_val_type = get_expr_type(arg_node); -// LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); -// LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, -// LLVMPointerType(union_val_type->type_ref, 0), ""); -// -// gen_assign_raw(g, arg_node, BinOpTypeAssign, bitcasted_union_field_ptr, new_union_val, -// union_val_type, union_val_type); -// -// } -// -// return tmp_struct_ptr; -// } -//} -// -//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeUnwrapErrorExpr); -// -// AstNode *op1 = node->data.unwrap_err_expr.op1; -// AstNode *op2 = node->data.unwrap_err_expr.op2; -// VariableTableEntry *var = node->data.unwrap_err_expr.var; -// -// LLVMValueRef expr_val = gen_expr(g, op1); -// TypeTableEntry *expr_type = get_expr_type(op1); -// TypeTableEntry *op2_type = get_expr_type(op2); -// assert(expr_type->id == TypeTableEntryIdErrorUnion); -// TypeTableEntry *child_type = expr_type->data.error.child_type; -// LLVMValueRef err_val; -// if (handle_is_ptr(expr_type)) { -// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, ""); -// err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); -// } else { -// err_val = expr_val; -// } -// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); -// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); -// -// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk"); -// LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError"); -// LLVMBasicBlockRef end_block; -// bool err_reachable = op2_type->id != TypeTableEntryIdUnreachable; -// bool have_end_block = err_reachable && type_has_bits(child_type); -// if (have_end_block) { -// end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrEnd"); -// } -// -// LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); -// -// LLVMPositionBuilderAtEnd(g->builder, err_block); -// if (var) { -// LLVMBuildStore(g->builder, err_val, var->value_ref); -// } -// LLVMValueRef err_result = gen_expr(g, op2); -// if (have_end_block) { -// LLVMBuildBr(g->builder, end_block); -// } else if (err_reachable) { -// LLVMBuildBr(g->builder, ok_block); -// } -// -// LLVMPositionBuilderAtEnd(g->builder, ok_block); -// if (!type_has_bits(child_type)) { -// return nullptr; -// } -// LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); -// LLVMValueRef child_val = get_handle_value(g, child_val_ptr, child_type); -// -// if (!have_end_block) { -// return child_val; -// } -// -// LLVMBuildBr(g->builder, end_block); -// -// LLVMPositionBuilderAtEnd(g->builder, end_block); -// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(err_result), ""); -// LLVMValueRef incoming_values[2] = {child_val, err_result}; -// LLVMBasicBlockRef incoming_blocks[2] = {ok_block, err_block}; -// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); -// return phi; -//} -// -//static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeReturnExpr); -// AstNode *param_node = node->data.return_expr.expr; -// assert(param_node); -// LLVMValueRef value = gen_expr(g, param_node); -// TypeTableEntry *value_type = get_expr_type(param_node); -// -// switch (node->data.return_expr.kind) { -// case ReturnKindUnconditional: -// { -// Expr *expr = get_resolved_expr(param_node); -// if (expr->const_val.ok) { -// if (value_type->id == TypeTableEntryIdErrorUnion) { -// if (expr->const_val.data.x_err.err) { -// expr->return_knowledge = ReturnKnowledgeKnownError; -// } else { -// expr->return_knowledge = ReturnKnowledgeKnownNonError; -// } -// } else if (value_type->id == TypeTableEntryIdMaybe) { -// if (expr->const_val.data.x_maybe) { -// expr->return_knowledge = ReturnKnowledgeKnownNonNull; -// } else { -// expr->return_knowledge = ReturnKnowledgeKnownNull; -// } -// } -// } -// return gen_return(g, node, value, expr->return_knowledge); -// } -// case ReturnKindError: -// { -// assert(value_type->id == TypeTableEntryIdErrorUnion); -// TypeTableEntry *child_type = value_type->data.error.child_type; -// -// LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetReturn"); -// LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetContinue"); -// -// LLVMValueRef err_val; -// if (type_has_bits(child_type)) { -// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, value, 0, ""); -// err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); -// } else { -// err_val = value; -// } -// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); -// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); -// LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block); -// -// LLVMPositionBuilderAtEnd(g->builder, return_block); -// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; -// if (return_type->id == TypeTableEntryIdPureError) { -// gen_return(g, node, err_val, ReturnKnowledgeKnownError); -// } else if (return_type->id == TypeTableEntryIdErrorUnion) { -// if (type_has_bits(return_type->data.error.child_type)) { -// assert(g->cur_ret_ptr); -// -// LLVMValueRef tag_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 0, ""); -// LLVMBuildStore(g->builder, err_val, tag_ptr); -// LLVMBuildRetVoid(g->builder); -// } else { -// gen_return(g, node, err_val, ReturnKnowledgeKnownError); -// } -// } else { -// zig_unreachable(); -// } -// -// LLVMPositionBuilderAtEnd(g->builder, continue_block); -// if (type_has_bits(child_type)) { -// LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); -// return get_handle_value(g, val_ptr, child_type); -// } else { -// return nullptr; -// } -// } -// } -// zig_unreachable(); -//} diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 8f9001edbd..85cbd67ba7 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -295,14 +295,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { return "?"; case IrUnOpError: return "%"; - case IrUnOpUnwrapError: - return "%%"; - case IrUnOpUnwrapMaybe: - return "??"; - case IrUnOpMaybeReturn: - return "?return"; - case IrUnOpErrorReturn: - return "%return"; } zig_unreachable(); } @@ -855,6 +847,51 @@ static void ir_print_overflow_op(IrPrint *irp, IrInstructionOverflowOp *instruct fprintf(irp->f, ")"); } +static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { + fprintf(irp->f, "@testError("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + +static void ir_print_err_union_type_child(IrPrint *irp, IrInstructionErrUnionTypeChild *instruction) { + fprintf(irp->f, "@errorUnionTypeChild("); + ir_print_other_instruction(irp, instruction->type_value); + fprintf(irp->f, ")"); +} + +static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { + fprintf(irp->f, "@unwrapErrorCode("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + +static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { + fprintf(irp->f, "@unwrapErrorPayload("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); + if (!instruction->safety_check_on) { + fprintf(irp->f, " // no safety"); + } +} + +static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionMaybeWrap *instruction) { + fprintf(irp->f, "@maybeWrap("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + +static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instruction) { + fprintf(irp->f, "@errWrapCode("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + +static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload *instruction) { + fprintf(irp->f, "@errWrapPayload("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1067,6 +1104,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdOverflowOp: ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction); break; + case IrInstructionIdTestErr: + ir_print_test_err(irp, (IrInstructionTestErr *)instruction); + break; + case IrInstructionIdUnwrapErrCode: + ir_print_unwrap_err_code(irp, (IrInstructionUnwrapErrCode *)instruction); + break; + case IrInstructionIdUnwrapErrPayload: + ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction); + break; + case IrInstructionIdErrUnionTypeChild: + ir_print_err_union_type_child(irp, (IrInstructionErrUnionTypeChild *)instruction); + break; + case IrInstructionIdMaybeWrap: + ir_print_maybe_wrap(irp, (IrInstructionMaybeWrap *)instruction); + break; + case IrInstructionIdErrWrapCode: + ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction); + break; + case IrInstructionIdErrWrapPayload: + ir_print_err_wrap_payload(irp, (IrInstructionErrWrapPayload *)instruction); + break; } fprintf(irp->f, "\n"); } |
