| ... | ... | @@ -1275,7 +1275,7 @@ pub const Object = struct { |
| 1275 | 1275 | .is_small = options.is_small, |
| 1276 | 1276 | .time_report = options.time_report, |
| 1277 | 1277 | .tsan = options.sanitize_thread, |
| 1278 | | .sancov = options.fuzz, |
| 1278 | .sancov = sanCovPassEnabled(comp.config.san_cov_trace_pc_guard), |
| 1279 | 1279 | .lto = options.lto, |
| 1280 | 1280 | .asm_filename = null, |
| 1281 | 1281 | .bin_filename = options.bin_path, |
| ... | ... | @@ -1283,19 +1283,19 @@ pub const Object = struct { |
| 1283 | 1283 | .bitcode_filename = null, |
| 1284 | 1284 | .coverage = .{ |
| 1285 | 1285 | .CoverageType = .Edge, |
| 1286 | | .IndirectCalls = true, |
| 1286 | .IndirectCalls = false, |
| 1287 | 1287 | .TraceBB = false, |
| 1288 | | .TraceCmp = true, |
| 1288 | .TraceCmp = false, |
| 1289 | 1289 | .TraceDiv = false, |
| 1290 | 1290 | .TraceGep = false, |
| 1291 | 1291 | .Use8bitCounters = false, |
| 1292 | 1292 | .TracePC = false, |
| 1293 | 1293 | .TracePCGuard = comp.config.san_cov_trace_pc_guard, |
| 1294 | | .Inline8bitCounters = true, |
| 1294 | .Inline8bitCounters = false, |
| 1295 | 1295 | .InlineBoolFlag = false, |
| 1296 | | .PCTable = true, |
| 1296 | .PCTable = false, |
| 1297 | 1297 | .NoPrune = false, |
| 1298 | | .StackDepth = true, |
| 1298 | .StackDepth = false, |
| 1299 | 1299 | .TraceLoads = false, |
| 1300 | 1300 | .TraceStores = false, |
| 1301 | 1301 | .CollectControlFlow = false, |
| ... | ... | @@ -1662,6 +1662,7 @@ pub const Object = struct { |
| 1662 | 1662 | .ng = &ng, |
| 1663 | 1663 | .wip = wip, |
| 1664 | 1664 | .is_naked = fn_info.cc == .Naked, |
| 1665 | .fuzz = owner_mod.fuzz and !func_analysis.disable_instrumentation and !is_naked, |
| 1665 | 1666 | .ret_ptr = ret_ptr, |
| 1666 | 1667 | .args = args.items, |
| 1667 | 1668 | .arg_index = 0, |
| ... | ... | @@ -1679,7 +1680,7 @@ pub const Object = struct { |
| 1679 | 1680 | defer fg.deinit(); |
| 1680 | 1681 | deinit_wip = false; |
| 1681 | 1682 | |
| 1682 | | fg.genBody(air.getMainBody()) catch |err| switch (err) { |
| 1683 | fg.genBody(air.getMainBody(), .poi) catch |err| switch (err) { |
| 1683 | 1684 | error.CodegenFail => { |
| 1684 | 1685 | try zcu.failed_codegen.put(zcu.gpa, func.owner_nav, ng.err_msg.?); |
| 1685 | 1686 | ng.err_msg = null; |
| ... | ... | @@ -4729,6 +4730,7 @@ pub const FuncGen = struct { |
| 4729 | 4730 | liveness: Liveness, |
| 4730 | 4731 | wip: Builder.WipFunction, |
| 4731 | 4732 | is_naked: bool, |
| 4733 | fuzz: bool, |
| 4732 | 4734 | |
| 4733 | 4735 | file: Builder.Metadata, |
| 4734 | 4736 | scope: Builder.Metadata, |
| ... | ... | @@ -4836,11 +4838,26 @@ pub const FuncGen = struct { |
| 4836 | 4838 | return o.null_opt_usize; |
| 4837 | 4839 | } |
| 4838 | 4840 | |
| 4839 | | fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void { |
| 4841 | fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: CoveragePoint) Error!void { |
| 4840 | 4842 | const o = self.ng.object; |
| 4841 | 4843 | const zcu = o.pt.zcu; |
| 4842 | 4844 | const ip = &zcu.intern_pool; |
| 4843 | 4845 | const air_tags = self.air.instructions.items(.tag); |
| 4846 | switch (coverage_point) { |
| 4847 | .none => {}, |
| 4848 | .poi => if (self.fuzz) |base_ptr| { |
| 4849 | // %0 = load i8, ptr @__sancov_gen_, align 1, !dbg !30, !nosanitize !28 |
| 4850 | // %1 = add i8 %0, 1, !dbg !30 |
| 4851 | // store i8 %1, ptr @__sancov_gen_, align 1, !dbg !30, !nosanitize !28 |
| 4852 | const ptr = try self.wip.gep(.inbounds, .i8, base_ptr, &.{ |
| 4853 | try o.builder.intValue(llvm_usize, self.nextPoiIndex()), |
| 4854 | }, ""); |
| 4855 | const counter = try self.wip.load(.normal, .i8, ptr, .default, ""); |
| 4856 | const one = try o.builder.intValue(.i8, 1); |
| 4857 | const counter_incremented = self.wip.bin(.add, counter, one, ""); |
| 4858 | try self.wip.store(.normal, counter_incremented, ptr, .default); |
| 4859 | }, |
| 4860 | } |
| 4844 | 4861 | for (body, 0..) |inst, i| { |
| 4845 | 4862 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue; |
| 4846 | 4863 | |
| ... | ... | @@ -5089,8 +5106,13 @@ pub const FuncGen = struct { |
| 5089 | 5106 | } |
| 5090 | 5107 | } |
| 5091 | 5108 | |
| 5092 | | fn genBodyDebugScope(self: *FuncGen, maybe_inline_func: ?InternPool.Index, body: []const Air.Inst.Index) Error!void { |
| 5093 | | if (self.wip.strip) return self.genBody(body); |
| 5109 | fn genBodyDebugScope( |
| 5110 | self: *FuncGen, |
| 5111 | maybe_inline_func: ?InternPool.Index, |
| 5112 | body: []const Air.Inst.Index, |
| 5113 | coverage_point: CoveragePoint, |
| 5114 | ) Error!void { |
| 5115 | if (self.wip.strip) return self.genBody(body, coverage_point); |
| 5094 | 5116 | |
| 5095 | 5117 | const old_file = self.file; |
| 5096 | 5118 | const old_inlined = self.inlined; |
| ... | ... | @@ -5137,7 +5159,8 @@ pub const FuncGen = struct { |
| 5137 | 5159 | .sp_flags = .{ |
| 5138 | 5160 | .Optimized = mod.optimize_mode != .Debug, |
| 5139 | 5161 | .Definition = true, |
| 5140 | | .LocalToUnit = true, // TODO: we can't know this at this point, since the function could be exported later! |
| 5162 | // TODO: we can't know this at this point, since the function could be exported later! |
| 5163 | .LocalToUnit = true, |
| 5141 | 5164 | }, |
| 5142 | 5165 | }, |
| 5143 | 5166 | o.debug_compile_unit, |
| ... | ... | @@ -5171,7 +5194,7 @@ pub const FuncGen = struct { |
| 5171 | 5194 | .no_location => {}, |
| 5172 | 5195 | }; |
| 5173 | 5196 | |
| 5174 | | try self.genBody(body); |
| 5197 | try self.genBody(body, coverage_point); |
| 5175 | 5198 | } |
| 5176 | 5199 | |
| 5177 | 5200 | pub const CallAttr = enum { |
| ... | ... | @@ -5881,7 +5904,7 @@ pub const FuncGen = struct { |
| 5881 | 5904 | const inst_ty = self.typeOfIndex(inst); |
| 5882 | 5905 | |
| 5883 | 5906 | if (inst_ty.isNoReturn(zcu)) { |
| 5884 | | try self.genBodyDebugScope(maybe_inline_func, body); |
| 5907 | try self.genBodyDebugScope(maybe_inline_func, body, .none); |
| 5885 | 5908 | return .none; |
| 5886 | 5909 | } |
| 5887 | 5910 | |
| ... | ... | @@ -5897,7 +5920,7 @@ pub const FuncGen = struct { |
| 5897 | 5920 | }); |
| 5898 | 5921 | defer assert(self.blocks.remove(inst)); |
| 5899 | 5922 | |
| 5900 | | try self.genBodyDebugScope(maybe_inline_func, body); |
| 5923 | try self.genBodyDebugScope(maybe_inline_func, body, .none); |
| 5901 | 5924 | |
| 5902 | 5925 | self.wip.cursor = .{ .block = parent_bb }; |
| 5903 | 5926 | |
| ... | ... | @@ -5996,11 +6019,11 @@ pub const FuncGen = struct { |
| 5996 | 6019 | |
| 5997 | 6020 | self.wip.cursor = .{ .block = then_block }; |
| 5998 | 6021 | if (hint == .then_cold) _ = try self.wip.callIntrinsicAssumeCold(); |
| 5999 | | try self.genBodyDebugScope(null, then_body); |
| 6022 | try self.genBodyDebugScope(null, then_body, .poi); |
| 6000 | 6023 | |
| 6001 | 6024 | self.wip.cursor = .{ .block = else_block }; |
| 6002 | 6025 | if (hint == .else_cold) _ = try self.wip.callIntrinsicAssumeCold(); |
| 6003 | | try self.genBodyDebugScope(null, else_body); |
| 6026 | try self.genBodyDebugScope(null, else_body, .poi); |
| 6004 | 6027 | |
| 6005 | 6028 | // No need to reset the insert cursor since this instruction is noreturn. |
| 6006 | 6029 | return .none; |
| ... | ... | @@ -6085,7 +6108,7 @@ pub const FuncGen = struct { |
| 6085 | 6108 | |
| 6086 | 6109 | fg.wip.cursor = .{ .block = return_block }; |
| 6087 | 6110 | if (err_cold) _ = try fg.wip.callIntrinsicAssumeCold(); |
| 6088 | | try fg.genBodyDebugScope(null, body); |
| 6111 | try fg.genBodyDebugScope(null, body, .poi); |
| 6089 | 6112 | |
| 6090 | 6113 | fg.wip.cursor = .{ .block = continue_block }; |
| 6091 | 6114 | } |
| ... | ... | @@ -6196,14 +6219,14 @@ pub const FuncGen = struct { |
| 6196 | 6219 | } |
| 6197 | 6220 | self.wip.cursor = .{ .block = case_block }; |
| 6198 | 6221 | if (switch_br.getHint(case.idx) == .cold) _ = try self.wip.callIntrinsicAssumeCold(); |
| 6199 | | try self.genBodyDebugScope(null, case.body); |
| 6222 | try self.genBodyDebugScope(null, case.body, .poi); |
| 6200 | 6223 | } |
| 6201 | 6224 | |
| 6202 | 6225 | const else_body = it.elseBody(); |
| 6203 | 6226 | self.wip.cursor = .{ .block = else_block }; |
| 6204 | 6227 | if (switch_br.getElseHint() == .cold) _ = try self.wip.callIntrinsicAssumeCold(); |
| 6205 | 6228 | if (else_body.len != 0) { |
| 6206 | | try self.genBodyDebugScope(null, else_body); |
| 6229 | try self.genBodyDebugScope(null, else_body, .poi); |
| 6207 | 6230 | } else { |
| 6208 | 6231 | _ = try self.wip.@"unreachable"(); |
| 6209 | 6232 | } |
| ... | ... | @@ -6222,7 +6245,7 @@ pub const FuncGen = struct { |
| 6222 | 6245 | _ = try self.wip.br(loop_block); |
| 6223 | 6246 | |
| 6224 | 6247 | self.wip.cursor = .{ .block = loop_block }; |
| 6225 | | try self.genBodyDebugScope(null, body); |
| 6248 | try self.genBodyDebugScope(null, body, .none); |
| 6226 | 6249 | |
| 6227 | 6250 | // TODO instead of this logic, change AIR to have the property that |
| 6228 | 6251 | // every block is guaranteed to end with a noreturn instruction. |
| ... | ... | @@ -12194,3 +12217,16 @@ pub fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { |
| 12194 | 12217 | => unreachable, |
| 12195 | 12218 | } |
| 12196 | 12219 | } |
| 12220 | |
| 12221 | fn sanCovPassEnabled(trace_pc_guard: bool) bool { |
| 12222 | return trace_pc_guard; |
| 12223 | } |
| 12224 | |
| 12225 | const CoveragePoint = enum { |
| 12226 | /// Indicates the block is not a place of interest corresponding to |
| 12227 | /// a source location for coverage purposes. |
| 12228 | none, |
| 12229 | /// Point of interest. The next instruction emitted corresponds to |
| 12230 | /// a source location used for coverage instrumentation. |
| 12231 | poi, |
| 12232 | }; |