Skip to content

Commit 01dba1c

Browse files
committed
Sema: add system for checking backend feature support
1 parent 0ecec5f commit 01dba1c

2 files changed

Lines changed: 49 additions & 65 deletions

File tree

src/Module.zig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6749,3 +6749,25 @@ pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {
67496749
return &[0]*Export{};
67506750
}
67516751
}
6752+
6753+
pub 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+
6762+
pub 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

Lines changed: 27 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,12 +1820,7 @@ fn analyzeAsType(
18201820
}
18211821

18221822
pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {
1823-
const backend_supports_error_return_tracing =
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-
}
1823+
if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
18291824

18301825
assert(!block.is_comptime);
18311826
var err_trace_block = block.makeSubBlock();
@@ -5906,9 +5901,8 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {
59065901
pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {
59075902
const src = sema.src;
59085903

5909-
const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
5910-
if (!backend_supports_error_return_tracing or !sema.mod.comp.bin_file.options.error_return_tracing)
5911-
return .none;
5904+
if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none;
5905+
if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none;
59125906

59135907
if (block.is_comptime)
59145908
return .none;
@@ -6146,8 +6140,7 @@ fn zirCall(
61466140
if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn)
61476141
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;
6150-
if (backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing and
6143+
if (sema.mod.backendSupportsFeature(.error_return_trace) and sema.mod.comp.bin_file.options.error_return_tracing and
61516144
!block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
61526145
{
61536146
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
79347927

79357928
try sema.requireRuntimeBlock(block, src, operand_src);
79367929
const result = try block.addTyOp(.intcast, dest_ty, operand);
7937-
if (block.wantSafety() and
7938-
!dest_ty.isNonexhaustiveEnum() and
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)
7930+
if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and
7931+
sema.mod.backendSupportsFeature(.is_named_enum_value))
79427932
{
79437933
const ok = try block.addUnOp(.is_named_enum_value, result);
79447934
try sema.addSafetyCheck(block, ok, .invalid_enum_value);
@@ -10656,8 +10646,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1065610646
return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
1065710647
}
1065810648

10659-
const backend_supports_is_named_enum = sema.mod.comp.bin_file.options.use_llvm;
10660-
1066110649
if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) {
1066210650
if (empty_enum) {
1066310651
return Air.Inst.Ref.void_value;
@@ -10668,7 +10656,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1066810656
if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) {
1066910657
return Air.Inst.Ref.unreachable_value;
1067010658
}
10671-
if (backend_supports_is_named_enum and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and
10659+
if (sema.mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and
1067210660
(!operand_ty.isNonexhaustiveEnum() or union_originally))
1067310661
{
1067410662
try sema.zirDbgStmt(block, cond_dbg_node_index);
@@ -11138,7 +11126,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1113811126
case_block.wip_capture_scope = wip_captures.scope;
1113911127
case_block.inline_case_capture = .none;
1114011128

11141-
if (backend_supports_is_named_enum and special.body.len != 0 and block.wantSafety() and
11129+
if (sema.mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
1114211130
operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally))
1114311131
{
1114411132
try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
@@ -11451,10 +11439,7 @@ fn validateSwitchNoRange(
1145111439
}
1145211440

1145311441
fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool {
11454-
const this_feature_is_implemented_in_the_backend =
11455-
sema.mod.comp.bin_file.options.use_llvm;
11456-
11457-
if (!this_feature_is_implemented_in_the_backend) return false;
11442+
if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) return false;
1145811443

1145911444
const tags = sema.code.instructions.items(.tag);
1146011445
for (body) |inst| {
@@ -16968,20 +16953,17 @@ fn retWithErrTracing(
1696816953
}
1696916954

1697016955
fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool {
16971-
// TODO implement this feature in all the backends and then delete this check.
16972-
const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
16956+
if (!sema.mod.backendSupportsFeature(.error_return_trace)) return false;
1697316957

1697416958
return fn_ret_ty.isError() and
16975-
sema.mod.comp.bin_file.options.error_return_tracing and
16976-
backend_supports_error_return_tracing;
16959+
sema.mod.comp.bin_file.options.error_return_tracing;
1697716960
}
1697816961

1697916962
fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
1698016963
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;
16983-
const ok = backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing;
16984-
if (!ok) return;
16965+
if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
16966+
if (!sema.mod.comp.bin_file.options.error_return_tracing) return;
1698516967

1698616968
// This is only relevant at runtime.
1698716969
if (block.is_comptime or block.is_typeof) return;
@@ -17003,11 +16985,9 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)
1700316985
// This is only relevant at runtime.
1700416986
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;
17007-
const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and
17008-
sema.mod.comp.bin_file.options.error_return_tracing and
17009-
backend_supports_error_return_tracing;
17010-
if (!ok) return;
16988+
if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
16989+
if (!sema.owner_func.?.calls_or_awaits_errorable_fn) return;
16990+
if (!sema.mod.comp.bin_file.options.error_return_tracing) return;
1701116991

1701216992
const tracy = trace(@src());
1701316993
defer tracy.end();
@@ -17986,14 +17966,10 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
1798617966
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
1798717967
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-
1799317969
if (sema.owner_func != null and
1799417970
sema.owner_func.?.calls_or_awaits_errorable_fn and
1799517971
sema.mod.comp.bin_file.options.error_return_tracing and
17996-
backend_supports_error_return_tracing)
17972+
sema.mod.backendSupportsFeature(.error_return_trace))
1799717973
{
1799817974
return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
1799917975
}
@@ -18173,7 +18149,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1817318149
return sema.addStrLit(block, field_name);
1817418150
}
1817518151
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)) {
1817718153
const ok = try block.addUnOp(.is_named_enum_value, casted_operand);
1817818154
try sema.addSafetyCheck(block, ok, .invalid_enum_value);
1817918155
}
@@ -19467,7 +19443,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1946719443
}
1946819444

1946919445
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)) {
1947119447
const err_int_inst = try block.addBitCast(Type.err_int, operand);
1947219448
const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
1947319449
try sema.addSafetyCheck(block, ok, .invalid_error_code);
@@ -22656,11 +22632,7 @@ fn panicWithMsg(
2265622632
const mod = sema.mod;
2265722633
const arena = sema.arena;
2265822634

22659-
const this_feature_is_implemented_in_the_backend =
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
22635+
if (!mod.backendSupportsFeature(.panic_fn)) {
2266422636
_ = try block.addNoOp(.breakpoint);
2266522637
_ = try block.addNoOp(.unreach);
2266622638
return;
@@ -22709,11 +22681,7 @@ fn panicUnwrapError(
2270922681
defer fail_block.instructions.deinit(gpa);
2271022682

2271122683
{
22712-
const this_feature_is_implemented_in_the_backend =
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
22684+
if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {
2271722685
_ = try fail_block.addNoOp(.breakpoint);
2271822686
_ = try fail_block.addNoOp(.unreach);
2271922687
} else {
@@ -22839,18 +22807,12 @@ fn safetyCheckFormatted(
2283922807

2284022808
defer fail_block.instructions.deinit(gpa);
2284122809

22842-
{
22843-
const this_feature_is_implemented_in_the_backend =
22844-
sema.mod.comp.bin_file.options.use_llvm;
22845-
22846-
if (!this_feature_is_implemented_in_the_backend) {
22847-
// TODO implement this feature in all the backends and then delete this branch
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-
}
22810+
if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {
22811+
_ = try fail_block.addNoOp(.breakpoint);
22812+
_ = try fail_block.addNoOp(.unreach);
22813+
} else {
22814+
const panic_fn = try sema.getBuiltin(func);
22815+
_ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null);
2285422816
}
2285522817
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
2285622818
}

0 commit comments

Comments
 (0)