authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-05 13:38:14+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-05 14:26:53+02:00
log01dba1c054724b4957778932fb5cd0df14d214b3
tree4344dda57656bebd2d548f5628843cf5194d4d6f
parent0ecec5fcca3ae8f33bf307c2ca66b8d11baf3d1d

Sema: add system for checking backend feature support


2 files changed, 49 insertions(+), 65 deletions(-)

src/Module.zig+22
...@@ -6749,3 +6749,25 @@ pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {...@@ -6749,3 +6749,25 @@ pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {
6749 return &[0]*Export{};6749 return &[0]*Export{};
6750 }6750 }
6751}6751}
6752
6753pub const Feature = enum {
6754 panic_fn,
6755 panic_unwrap_error,
6756 safety_check_formatted,
6757 error_return_trace,
6758 is_named_enum_value,
6759 error_set_has_value,
6760};
6761
6762pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {
6763 return switch (feature) {
6764 .panic_fn => mod.comp.bin_file.options.target.ofmt == .c or
6765 mod.comp.bin_file.options.use_llvm,
6766 .panic_unwrap_error => mod.comp.bin_file.options.target.ofmt == .c or
6767 mod.comp.bin_file.options.use_llvm,
6768 .safety_check_formatted => mod.comp.bin_file.options.use_llvm,
6769 .error_return_trace => mod.comp.bin_file.options.use_llvm,
6770 .is_named_enum_value => mod.comp.bin_file.options.use_llvm,
6771 .error_set_has_value => mod.comp.bin_file.options.use_llvm,
6772 };
6773}
src/Sema.zig+27-65
...@@ -1820,12 +1820,7 @@ fn analyzeAsType(...@@ -1820,12 +1820,7 @@ fn analyzeAsType(
1820}1820}
18211821
1822pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {1822pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {
1823 const backend_supports_error_return_tracing =1823 if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
1824 sema.mod.comp.bin_file.options.use_llvm;
1825 if (!backend_supports_error_return_tracing) {
1826 // TODO implement this feature in all the backends and then delete this branch
1827 return;
1828 }
18291824
1830 assert(!block.is_comptime);1825 assert(!block.is_comptime);
1831 var err_trace_block = block.makeSubBlock();1826 var err_trace_block = block.makeSubBlock();
...@@ -5906,9 +5901,8 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {...@@ -5906,9 +5901,8 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {
5906pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {5901pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {
5907 const src = sema.src;5902 const src = sema.src;
59085903
5909 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;5904 if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none;
5910 if (!backend_supports_error_return_tracing or !sema.mod.comp.bin_file.options.error_return_tracing)5905 if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none;
5911 return .none;
59125906
5913 if (block.is_comptime)5907 if (block.is_comptime)
5914 return .none;5908 return .none;
...@@ -6146,8 +6140,7 @@ fn zirCall(...@@ -6146,8 +6140,7 @@ fn zirCall(
6146 if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn)6140 if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn)
6147 input_is_error = false; // input was an error type, but no errorable fn's were actually called6141 input_is_error = false; // input was an error type, but no errorable fn's were actually called
61486142
6149 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;6143 if (sema.mod.backendSupportsFeature(.error_return_trace) and sema.mod.comp.bin_file.options.error_return_tracing and
6150 if (backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing and
6151 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))6144 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
6152 {6145 {
6153 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {6146 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
...@@ -7934,11 +7927,8 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -7934,11 +7927,8 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
79347927
7935 try sema.requireRuntimeBlock(block, src, operand_src);7928 try sema.requireRuntimeBlock(block, src, operand_src);
7936 const result = try block.addTyOp(.intcast, dest_ty, operand);7929 const result = try block.addTyOp(.intcast, dest_ty, operand);
7937 if (block.wantSafety() and7930 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and
7938 !dest_ty.isNonexhaustiveEnum() and7931 sema.mod.backendSupportsFeature(.is_named_enum_value))
7939 // TODO instead of "use_llvm", check a different condition so that backends
7940 // can advertise themselves as supporting these extra AIR instructions for safety.
7941 sema.mod.comp.bin_file.options.use_llvm)
7942 {7932 {
7943 const ok = try block.addUnOp(.is_named_enum_value, result);7933 const ok = try block.addUnOp(.is_named_enum_value, result);
7944 try sema.addSafetyCheck(block, ok, .invalid_enum_value);7934 try sema.addSafetyCheck(block, ok, .invalid_enum_value);
...@@ -10656,8 +10646,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10656,8 +10646,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10656 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);10646 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
10657 }10647 }
1065810648
10659 const backend_supports_is_named_enum = sema.mod.comp.bin_file.options.use_llvm;
10660
10661 if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) {10649 if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) {
10662 if (empty_enum) {10650 if (empty_enum) {
10663 return Air.Inst.Ref.void_value;10651 return Air.Inst.Ref.void_value;
...@@ -10668,7 +10656,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10668,7 +10656,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10668 if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) {10656 if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) {
10669 return Air.Inst.Ref.unreachable_value;10657 return Air.Inst.Ref.unreachable_value;
10670 }10658 }
10671 if (backend_supports_is_named_enum and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and10659 if (sema.mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and
10672 (!operand_ty.isNonexhaustiveEnum() or union_originally))10660 (!operand_ty.isNonexhaustiveEnum() or union_originally))
10673 {10661 {
10674 try sema.zirDbgStmt(block, cond_dbg_node_index);10662 try sema.zirDbgStmt(block, cond_dbg_node_index);
...@@ -11138,7 +11126,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11138,7 +11126,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11138 case_block.wip_capture_scope = wip_captures.scope;11126 case_block.wip_capture_scope = wip_captures.scope;
11139 case_block.inline_case_capture = .none;11127 case_block.inline_case_capture = .none;
1114011128
11141 if (backend_supports_is_named_enum and special.body.len != 0 and block.wantSafety() and11129 if (sema.mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
11142 operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally))11130 operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally))
11143 {11131 {
11144 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);11132 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
...@@ -11451,10 +11439,7 @@ fn validateSwitchNoRange(...@@ -11451,10 +11439,7 @@ fn validateSwitchNoRange(
11451}11439}
1145211440
11453fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool {11441fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool {
11454 const this_feature_is_implemented_in_the_backend =11442 if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) return false;
11455 sema.mod.comp.bin_file.options.use_llvm;
11456
11457 if (!this_feature_is_implemented_in_the_backend) return false;
1145811443
11459 const tags = sema.code.instructions.items(.tag);11444 const tags = sema.code.instructions.items(.tag);
11460 for (body) |inst| {11445 for (body) |inst| {
...@@ -16968,20 +16953,17 @@ fn retWithErrTracing(...@@ -16968,20 +16953,17 @@ fn retWithErrTracing(
16968}16953}
1696916954
16970fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool {16955fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool {
16971 // TODO implement this feature in all the backends and then delete this check.16956 if (!sema.mod.backendSupportsFeature(.error_return_trace)) return false;
16972 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
1697316957
16974 return fn_ret_ty.isError() and16958 return fn_ret_ty.isError() and
16975 sema.mod.comp.bin_file.options.error_return_tracing and16959 sema.mod.comp.bin_file.options.error_return_tracing;
16976 backend_supports_error_return_tracing;
16977}16960}
1697816961
16979fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {16962fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
16980 const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index;16963 const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index;
1698116964
16982 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;16965 if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
16983 const ok = backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing;16966 if (!sema.mod.comp.bin_file.options.error_return_tracing) return;
16984 if (!ok) return;
1698516967
16986 // This is only relevant at runtime.16968 // This is only relevant at runtime.
16987 if (block.is_comptime or block.is_typeof) return;16969 if (block.is_comptime or block.is_typeof) return;
...@@ -17003,11 +16985,9 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)...@@ -17003,11 +16985,9 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)
17003 // This is only relevant at runtime.16985 // This is only relevant at runtime.
17004 if (start_block.is_comptime or start_block.is_typeof) return;16986 if (start_block.is_comptime or start_block.is_typeof) return;
1700516987
17006 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;16988 if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
17007 const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and16989 if (!sema.owner_func.?.calls_or_awaits_errorable_fn) return;
17008 sema.mod.comp.bin_file.options.error_return_tracing and16990 if (!sema.mod.comp.bin_file.options.error_return_tracing) return;
17009 backend_supports_error_return_tracing;
17010 if (!ok) return;
1701116991
17012 const tracy = trace(@src());16992 const tracy = trace(@src());
17013 defer tracy.end();16993 defer tracy.end();
...@@ -17986,14 +17966,10 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {...@@ -17986,14 +17966,10 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
17986 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);17966 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
17987 const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);17967 const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
1798817968
17989 // TODO implement this feature in all the backends and then delete this check.
17990 const backend_supports_error_return_tracing =
17991 sema.mod.comp.bin_file.options.use_llvm;
17992
17993 if (sema.owner_func != null and17969 if (sema.owner_func != null and
17994 sema.owner_func.?.calls_or_awaits_errorable_fn and17970 sema.owner_func.?.calls_or_awaits_errorable_fn and
17995 sema.mod.comp.bin_file.options.error_return_tracing and17971 sema.mod.comp.bin_file.options.error_return_tracing and
17996 backend_supports_error_return_tracing)17972 sema.mod.backendSupportsFeature(.error_return_trace))
17997 {17973 {
17998 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);17974 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
17999 }17975 }
...@@ -18173,7 +18149,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18173,7 +18149,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18173 return sema.addStrLit(block, field_name);18149 return sema.addStrLit(block, field_name);
18174 }18150 }
18175 try sema.requireRuntimeBlock(block, src, operand_src);18151 try sema.requireRuntimeBlock(block, src, operand_src);
18176 if (block.wantSafety() and sema.mod.comp.bin_file.options.use_llvm) {18152 if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {
18177 const ok = try block.addUnOp(.is_named_enum_value, casted_operand);18153 const ok = try block.addUnOp(.is_named_enum_value, casted_operand);
18178 try sema.addSafetyCheck(block, ok, .invalid_enum_value);18154 try sema.addSafetyCheck(block, ok, .invalid_enum_value);
18179 }18155 }
...@@ -19467,7 +19443,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -19467,7 +19443,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
19467 }19443 }
1946819444
19469 try sema.requireRuntimeBlock(block, src, operand_src);19445 try sema.requireRuntimeBlock(block, src, operand_src);
19470 if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) {19446 if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.backendSupportsFeature(.error_set_has_value)) {
19471 const err_int_inst = try block.addBitCast(Type.err_int, operand);19447 const err_int_inst = try block.addBitCast(Type.err_int, operand);
19472 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);19448 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
19473 try sema.addSafetyCheck(block, ok, .invalid_error_code);19449 try sema.addSafetyCheck(block, ok, .invalid_error_code);
...@@ -22656,11 +22632,7 @@ fn panicWithMsg(...@@ -22656,11 +22632,7 @@ fn panicWithMsg(
22656 const mod = sema.mod;22632 const mod = sema.mod;
22657 const arena = sema.arena;22633 const arena = sema.arena;
2265822634
22659 const this_feature_is_implemented_in_the_backend =22635 if (!mod.backendSupportsFeature(.panic_fn)) {
22660 mod.comp.bin_file.options.target.ofmt == .c or
22661 mod.comp.bin_file.options.use_llvm;
22662 if (!this_feature_is_implemented_in_the_backend) {
22663 // TODO implement this feature in all the backends and then delete this branch
22664 _ = try block.addNoOp(.breakpoint);22636 _ = try block.addNoOp(.breakpoint);
22665 _ = try block.addNoOp(.unreach);22637 _ = try block.addNoOp(.unreach);
22666 return;22638 return;
...@@ -22709,11 +22681,7 @@ fn panicUnwrapError(...@@ -22709,11 +22681,7 @@ fn panicUnwrapError(
22709 defer fail_block.instructions.deinit(gpa);22681 defer fail_block.instructions.deinit(gpa);
2271022682
22711 {22683 {
22712 const this_feature_is_implemented_in_the_backend =22684 if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {
22713 sema.mod.comp.bin_file.options.use_llvm;
22714
22715 if (!this_feature_is_implemented_in_the_backend) {
22716 // TODO implement this feature in all the backends and then delete this branch
22717 _ = try fail_block.addNoOp(.breakpoint);22685 _ = try fail_block.addNoOp(.breakpoint);
22718 _ = try fail_block.addNoOp(.unreach);22686 _ = try fail_block.addNoOp(.unreach);
22719 } else {22687 } else {
...@@ -22839,18 +22807,12 @@ fn safetyCheckFormatted(...@@ -22839,18 +22807,12 @@ fn safetyCheckFormatted(
2283922807
22840 defer fail_block.instructions.deinit(gpa);22808 defer fail_block.instructions.deinit(gpa);
2284122809
22842 {22810 if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {
22843 const this_feature_is_implemented_in_the_backend =22811 _ = try fail_block.addNoOp(.breakpoint);
22844 sema.mod.comp.bin_file.options.use_llvm;22812 _ = try fail_block.addNoOp(.unreach);
2284522813 } else {
22846 if (!this_feature_is_implemented_in_the_backend) {22814 const panic_fn = try sema.getBuiltin(func);
22847 // TODO implement this feature in all the backends and then delete this branch22815 _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null);
22848 _ = try fail_block.addNoOp(.breakpoint);
22849 _ = try fail_block.addNoOp(.unreach);
22850 } else {
22851 const panic_fn = try sema.getBuiltin(func);
22852 _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null);
22853 }
22854 }22816 }
22855 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);22817 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
22856}22818}