| ... | @@ -1275,7 +1275,7 @@ pub const Object = struct { | ... | @@ -1275,7 +1275,7 @@ pub const Object = struct { |
| 1275 | .is_small = options.is_small, | 1275 | .is_small = options.is_small, |
| 1276 | .time_report = options.time_report, | 1276 | .time_report = options.time_report, |
| 1277 | .tsan = options.sanitize_thread, | 1277 | .tsan = options.sanitize_thread, |
| 1278 | .sancov = options.fuzz, | 1278 | .sancov = sanCovPassEnabled(comp.config.san_cov_trace_pc_guard), |
| 1279 | .lto = options.lto, | 1279 | .lto = options.lto, |
| 1280 | .asm_filename = null, | 1280 | .asm_filename = null, |
| 1281 | .bin_filename = options.bin_path, | 1281 | .bin_filename = options.bin_path, |
| ... | @@ -1283,19 +1283,19 @@ pub const Object = struct { | ... | @@ -1283,19 +1283,19 @@ pub const Object = struct { |
| 1283 | .bitcode_filename = null, | 1283 | .bitcode_filename = null, |
| 1284 | .coverage = .{ | 1284 | .coverage = .{ |
| 1285 | .CoverageType = .Edge, | 1285 | .CoverageType = .Edge, |
| 1286 | .IndirectCalls = true, | 1286 | .IndirectCalls = false, |
| 1287 | .TraceBB = false, | 1287 | .TraceBB = false, |
| 1288 | .TraceCmp = true, | 1288 | .TraceCmp = false, |
| 1289 | .TraceDiv = false, | 1289 | .TraceDiv = false, |
| 1290 | .TraceGep = false, | 1290 | .TraceGep = false, |
| 1291 | .Use8bitCounters = false, | 1291 | .Use8bitCounters = false, |
| 1292 | .TracePC = false, | 1292 | .TracePC = false, |
| 1293 | .TracePCGuard = comp.config.san_cov_trace_pc_guard, | 1293 | .TracePCGuard = comp.config.san_cov_trace_pc_guard, |
| 1294 | .Inline8bitCounters = true, | 1294 | .Inline8bitCounters = false, |
| 1295 | .InlineBoolFlag = false, | 1295 | .InlineBoolFlag = false, |
| 1296 | .PCTable = true, | 1296 | .PCTable = false, |
| 1297 | .NoPrune = false, | 1297 | .NoPrune = false, |
| 1298 | .StackDepth = true, | 1298 | .StackDepth = false, |
| 1299 | .TraceLoads = false, | 1299 | .TraceLoads = false, |
| 1300 | .TraceStores = false, | 1300 | .TraceStores = false, |
| 1301 | .CollectControlFlow = false, | 1301 | .CollectControlFlow = false, |
| ... | @@ -1662,6 +1662,7 @@ pub const Object = struct { | ... | @@ -1662,6 +1662,7 @@ pub const Object = struct { |
| 1662 | .ng = &ng, | 1662 | .ng = &ng, |
| 1663 | .wip = wip, | 1663 | .wip = wip, |
| 1664 | .is_naked = fn_info.cc == .Naked, | 1664 | .is_naked = fn_info.cc == .Naked, |
| | 1665 | .fuzz = owner_mod.fuzz and !func_analysis.disable_instrumentation and !is_naked, |
| 1665 | .ret_ptr = ret_ptr, | 1666 | .ret_ptr = ret_ptr, |
| 1666 | .args = args.items, | 1667 | .args = args.items, |
| 1667 | .arg_index = 0, | 1668 | .arg_index = 0, |
| ... | @@ -1679,7 +1680,7 @@ pub const Object = struct { | ... | @@ -1679,7 +1680,7 @@ pub const Object = struct { |
| 1679 | defer fg.deinit(); | 1680 | defer fg.deinit(); |
| 1680 | deinit_wip = false; | 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 | error.CodegenFail => { | 1684 | error.CodegenFail => { |
| 1684 | try zcu.failed_codegen.put(zcu.gpa, func.owner_nav, ng.err_msg.?); | 1685 | try zcu.failed_codegen.put(zcu.gpa, func.owner_nav, ng.err_msg.?); |
| 1685 | ng.err_msg = null; | 1686 | ng.err_msg = null; |
| ... | @@ -4729,6 +4730,7 @@ pub const FuncGen = struct { | ... | @@ -4729,6 +4730,7 @@ pub const FuncGen = struct { |
| 4729 | liveness: Liveness, | 4730 | liveness: Liveness, |
| 4730 | wip: Builder.WipFunction, | 4731 | wip: Builder.WipFunction, |
| 4731 | is_naked: bool, | 4732 | is_naked: bool, |
| | 4733 | fuzz: bool, |
| 4732 | | 4734 | |
| 4733 | file: Builder.Metadata, | 4735 | file: Builder.Metadata, |
| 4734 | scope: Builder.Metadata, | 4736 | scope: Builder.Metadata, |
| ... | @@ -4836,11 +4838,26 @@ pub const FuncGen = struct { | ... | @@ -4836,11 +4838,26 @@ pub const FuncGen = struct { |
| 4836 | return o.null_opt_usize; | 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 | const o = self.ng.object; | 4842 | const o = self.ng.object; |
| 4841 | const zcu = o.pt.zcu; | 4843 | const zcu = o.pt.zcu; |
| 4842 | const ip = &zcu.intern_pool; | 4844 | const ip = &zcu.intern_pool; |
| 4843 | const air_tags = self.air.instructions.items(.tag); | 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 | for (body, 0..) |inst, i| { | 4861 | for (body, 0..) |inst, i| { |
| 4845 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue; | 4862 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue; |
| 4846 | | 4863 | |
| ... | @@ -5089,8 +5106,13 @@ pub const FuncGen = struct { | ... | @@ -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 { | 5109 | fn genBodyDebugScope( |
| 5093 | if (self.wip.strip) return self.genBody(body); | 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 | const old_file = self.file; | 5117 | const old_file = self.file; |
| 5096 | const old_inlined = self.inlined; | 5118 | const old_inlined = self.inlined; |
| ... | @@ -5137,7 +5159,8 @@ pub const FuncGen = struct { | ... | @@ -5137,7 +5159,8 @@ pub const FuncGen = struct { |
| 5137 | .sp_flags = .{ | 5159 | .sp_flags = .{ |
| 5138 | .Optimized = mod.optimize_mode != .Debug, | 5160 | .Optimized = mod.optimize_mode != .Debug, |
| 5139 | .Definition = true, | 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 | o.debug_compile_unit, | 5166 | o.debug_compile_unit, |
| ... | @@ -5171,7 +5194,7 @@ pub const FuncGen = struct { | ... | @@ -5171,7 +5194,7 @@ pub const FuncGen = struct { |
| 5171 | .no_location => {}, | 5194 | .no_location => {}, |
| 5172 | }; | 5195 | }; |
| 5173 | | 5196 | |
| 5174 | try self.genBody(body); | 5197 | try self.genBody(body, coverage_point); |
| 5175 | } | 5198 | } |
| 5176 | | 5199 | |
| 5177 | pub const CallAttr = enum { | 5200 | pub const CallAttr = enum { |
| ... | @@ -5881,7 +5904,7 @@ pub const FuncGen = struct { | ... | @@ -5881,7 +5904,7 @@ pub const FuncGen = struct { |
| 5881 | const inst_ty = self.typeOfIndex(inst); | 5904 | const inst_ty = self.typeOfIndex(inst); |
| 5882 | | 5905 | |
| 5883 | if (inst_ty.isNoReturn(zcu)) { | 5906 | if (inst_ty.isNoReturn(zcu)) { |
| 5884 | try self.genBodyDebugScope(maybe_inline_func, body); | 5907 | try self.genBodyDebugScope(maybe_inline_func, body, .none); |
| 5885 | return .none; | 5908 | return .none; |
| 5886 | } | 5909 | } |
| 5887 | | 5910 | |
| ... | @@ -5897,7 +5920,7 @@ pub const FuncGen = struct { | ... | @@ -5897,7 +5920,7 @@ pub const FuncGen = struct { |
| 5897 | }); | 5920 | }); |
| 5898 | defer assert(self.blocks.remove(inst)); | 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 | self.wip.cursor = .{ .block = parent_bb }; | 5925 | self.wip.cursor = .{ .block = parent_bb }; |
| 5903 | | 5926 | |
| ... | @@ -5996,11 +6019,11 @@ pub const FuncGen = struct { | ... | @@ -5996,11 +6019,11 @@ pub const FuncGen = struct { |
| 5996 | | 6019 | |
| 5997 | self.wip.cursor = .{ .block = then_block }; | 6020 | self.wip.cursor = .{ .block = then_block }; |
| 5998 | if (hint == .then_cold) _ = try self.wip.callIntrinsicAssumeCold(); | 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 | self.wip.cursor = .{ .block = else_block }; | 6024 | self.wip.cursor = .{ .block = else_block }; |
| 6002 | if (hint == .else_cold) _ = try self.wip.callIntrinsicAssumeCold(); | 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 | // No need to reset the insert cursor since this instruction is noreturn. | 6028 | // No need to reset the insert cursor since this instruction is noreturn. |
| 6006 | return .none; | 6029 | return .none; |
| ... | @@ -6085,7 +6108,7 @@ pub const FuncGen = struct { | ... | @@ -6085,7 +6108,7 @@ pub const FuncGen = struct { |
| 6085 | | 6108 | |
| 6086 | fg.wip.cursor = .{ .block = return_block }; | 6109 | fg.wip.cursor = .{ .block = return_block }; |
| 6087 | if (err_cold) _ = try fg.wip.callIntrinsicAssumeCold(); | 6110 | if (err_cold) _ = try fg.wip.callIntrinsicAssumeCold(); |
| 6088 | try fg.genBodyDebugScope(null, body); | 6111 | try fg.genBodyDebugScope(null, body, .poi); |
| 6089 | | 6112 | |
| 6090 | fg.wip.cursor = .{ .block = continue_block }; | 6113 | fg.wip.cursor = .{ .block = continue_block }; |
| 6091 | } | 6114 | } |
| ... | @@ -6196,14 +6219,14 @@ pub const FuncGen = struct { | ... | @@ -6196,14 +6219,14 @@ pub const FuncGen = struct { |
| 6196 | } | 6219 | } |
| 6197 | self.wip.cursor = .{ .block = case_block }; | 6220 | self.wip.cursor = .{ .block = case_block }; |
| 6198 | if (switch_br.getHint(case.idx) == .cold) _ = try self.wip.callIntrinsicAssumeCold(); | 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 | const else_body = it.elseBody(); | 6225 | const else_body = it.elseBody(); |
| 6203 | self.wip.cursor = .{ .block = else_block }; | 6226 | self.wip.cursor = .{ .block = else_block }; |
| 6204 | if (switch_br.getElseHint() == .cold) _ = try self.wip.callIntrinsicAssumeCold(); | 6227 | if (switch_br.getElseHint() == .cold) _ = try self.wip.callIntrinsicAssumeCold(); |
| 6205 | if (else_body.len != 0) { | 6228 | if (else_body.len != 0) { |
| 6206 | try self.genBodyDebugScope(null, else_body); | 6229 | try self.genBodyDebugScope(null, else_body, .poi); |
| 6207 | } else { | 6230 | } else { |
| 6208 | _ = try self.wip.@"unreachable"(); | 6231 | _ = try self.wip.@"unreachable"(); |
| 6209 | } | 6232 | } |
| ... | @@ -6222,7 +6245,7 @@ pub const FuncGen = struct { | ... | @@ -6222,7 +6245,7 @@ pub const FuncGen = struct { |
| 6222 | _ = try self.wip.br(loop_block); | 6245 | _ = try self.wip.br(loop_block); |
| 6223 | | 6246 | |
| 6224 | self.wip.cursor = .{ .block = loop_block }; | 6247 | self.wip.cursor = .{ .block = loop_block }; |
| 6225 | try self.genBodyDebugScope(null, body); | 6248 | try self.genBodyDebugScope(null, body, .none); |
| 6226 | | 6249 | |
| 6227 | // TODO instead of this logic, change AIR to have the property that | 6250 | // TODO instead of this logic, change AIR to have the property that |
| 6228 | // every block is guaranteed to end with a noreturn instruction. | 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,3 +12217,16 @@ pub fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { |
| 12194 | => unreachable, | 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 | }; |