authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-02-24 08:25:23+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-02-24 08:25:23+01:00
logecc76348e6858f00b920d8dc9e44a6e703d8e497
tree018e151e85958c8e1b12328865e8b18398956b5e
parent76558f8c6b8361ab520ea77e4b4cd2bfc8f688ad
parente11ac026623f8d0f4895cddd6a9bf3c03a866c6d
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22154 from alexrp/disable-intrinsics

compiler: Implement `@disableIntrinsics()` builtin function.

10 files changed, 107 insertions(+), 28 deletions(-)

lib/std/zig/AstGen.zig+2
......@@ -2956,6 +2956,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
29562956 .extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
29572957 .breakpoint,
29582958 .disable_instrumentation,
2959 .disable_intrinsics,
29592960 .set_float_mode,
29602961 .branch_hint,
29612962 => break :b true,
......@@ -9578,6 +9579,7 @@ fn builtinCall(
95789579 .frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node),
95799580 .breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node),
95809581 .disable_instrumentation => return rvalue(gz, ri, try gz.addNodeExtended(.disable_instrumentation, node), node),
9582 .disable_intrinsics => return rvalue(gz, ri, try gz.addNodeExtended(.disable_intrinsics, node), node),
95819583
95829584 .type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info),
95839585 .size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of),
lib/std/zig/AstRlAnnotate.zig+1
......@@ -882,6 +882,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
882882 .frame,
883883 .breakpoint,
884884 .disable_instrumentation,
885 .disable_intrinsics,
885886 .in_comptime,
886887 .panic,
887888 .trap,
lib/std/zig/BuiltinFn.zig+9
......@@ -15,6 +15,7 @@ pub const Tag = enum {
1515 branch_hint,
1616 breakpoint,
1717 disable_instrumentation,
18 disable_intrinsics,
1819 mul_add,
1920 byte_swap,
2021 bit_reverse,
......@@ -262,6 +263,14 @@ pub const list = list: {
262263 .illegal_outside_function = true,
263264 },
264265 },
266 .{
267 "@disableIntrinsics",
268 .{
269 .tag = .disable_intrinsics,
270 .param_count = 0,
271 .illegal_outside_function = true,
272 },
273 },
265274 .{
266275 "@mulAdd",
267276 .{
lib/std/zig/Zir.zig+8-1
......@@ -1587,7 +1587,11 @@ pub const Inst = struct {
15871587 => false,
15881588
15891589 .extended => switch (data.extended.opcode) {
1590 .branch_hint, .breakpoint, .disable_instrumentation => true,
1590 .branch_hint,
1591 .breakpoint,
1592 .disable_instrumentation,
1593 .disable_intrinsics,
1594 => true,
15911595 else => false,
15921596 },
15931597 };
......@@ -2004,6 +2008,8 @@ pub const Inst = struct {
20042008 breakpoint,
20052009 /// Implement builtin `@disableInstrumentation`. `operand` is `src_node: i32`.
20062010 disable_instrumentation,
2011 /// Implement builtin `@disableIntrinsics`. `operand` is `src_node: i32`.
2012 disable_intrinsics,
20072013 /// Implements the `@select` builtin.
20082014 /// `operand` is payload index to `Select`.
20092015 select,
......@@ -4332,6 +4338,7 @@ fn findTrackableInner(
43324338 .await_nosuspend,
43334339 .breakpoint,
43344340 .disable_instrumentation,
4341 .disable_intrinsics,
43354342 .select,
43364343 .int_from_error,
43374344 .error_from_int,
lib/zig.h+6
......@@ -223,6 +223,12 @@
223223#define zig_restrict
224224#endif
225225
226#if zig_has_attribute(no_builtin)
227#define zig_no_builtin __attribute__((no_builtin))
228#else
229#define zig_no_builtin
230#endif
231
226232#if zig_has_attribute(aligned) || defined(zig_tinyc)
227233#define zig_under_align(alignment) __attribute__((aligned(alignment)))
228234#elif defined(zig_msvc)
src/InternPool.zig+18-1
......@@ -6045,8 +6045,9 @@ pub const FuncAnalysis = packed struct(u32) {
60456045 /// True if this function has an inferred error set.
60466046 inferred_error_set: bool,
60476047 disable_instrumentation: bool,
6048 disable_intrinsics: bool,
60486049
6049 _: u24 = 0,
6050 _: u23 = 0,
60506051};
60516052
60526053pub const Bytes = struct {
......@@ -9077,6 +9078,7 @@ pub fn getFuncDecl(
90779078 .has_error_trace = false,
90789079 .inferred_error_set = false,
90799080 .disable_instrumentation = false,
9081 .disable_intrinsics = false,
90809082 },
90819083 .owner_nav = key.owner_nav,
90829084 .ty = key.ty,
......@@ -9186,6 +9188,7 @@ pub fn getFuncDeclIes(
91869188 .has_error_trace = false,
91879189 .inferred_error_set = true,
91889190 .disable_instrumentation = false,
9191 .disable_intrinsics = false,
91899192 },
91909193 .owner_nav = key.owner_nav,
91919194 .ty = func_ty,
......@@ -9382,6 +9385,7 @@ pub fn getFuncInstance(
93829385 .has_error_trace = false,
93839386 .inferred_error_set = false,
93849387 .disable_instrumentation = false,
9388 .disable_intrinsics = false,
93859389 },
93869390 // This is populated after we create the Nav below. It is not read
93879391 // by equality or hashing functions.
......@@ -9480,6 +9484,7 @@ pub fn getFuncInstanceIes(
94809484 .has_error_trace = false,
94819485 .inferred_error_set = true,
94829486 .disable_instrumentation = false,
9487 .disable_intrinsics = false,
94839488 },
94849489 // This is populated after we create the Nav below. It is not read
94859490 // by equality or hashing functions.
......@@ -12313,6 +12318,18 @@ pub fn funcSetDisableInstrumentation(ip: *InternPool, func: Index) void {
1231312318 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
1231412319}
1231512320
12321pub fn funcSetDisableIntrinsics(ip: *InternPool, func: Index) void {
12322 const unwrapped_func = func.unwrap(ip);
12323 const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
12324 extra_mutex.lock();
12325 defer extra_mutex.unlock();
12326
12327 const analysis_ptr = ip.funcAnalysisPtr(func);
12328 var analysis = analysis_ptr.*;
12329 analysis.disable_intrinsics = true;
12330 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
12331}
12332
1231612333pub fn funcZirBodyInst(ip: *const InternPool, func: Index) TrackedInst.Index {
1231712334 const unwrapped_func = func.unwrap(ip);
1231812335 const item = unwrapped_func.getItem(ip);
src/Sema.zig+22
......@@ -1409,6 +1409,11 @@ fn analyzeBodyInner(
14091409 i += 1;
14101410 continue;
14111411 },
1412 .disable_intrinsics => {
1413 try sema.zirDisableIntrinsics();
1414 i += 1;
1415 continue;
1416 },
14121417 .restore_err_ret_index => {
14131418 try sema.zirRestoreErrRetIndex(block, extended);
14141419 i += 1;
......@@ -6642,6 +6647,23 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
66426647 sema.allow_memoize = false;
66436648}
66446649
6650fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
6651 const pt = sema.pt;
6652 const zcu = pt.zcu;
6653 const ip = &zcu.intern_pool;
6654 const func = switch (sema.owner.unwrap()) {
6655 .func => |func| func,
6656 .@"comptime",
6657 .nav_val,
6658 .nav_ty,
6659 .type,
6660 .memoized_state,
6661 => return, // does nothing outside a function
6662 };
6663 ip.funcSetDisableIntrinsics(func);
6664 sema.allow_memoize = false;
6665}
6666
66456667fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
66466668 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
66476669 const src = block.builtinCallArgSrc(extra.node, 0);
src/codegen/c.zig+11-2
......@@ -1859,8 +1859,17 @@ pub const DeclGen = struct {
18591859 else => unreachable,
18601860 }
18611861 }
1862 if (fn_val.getFunction(zcu)) |func| if (func.analysisUnordered(ip).branch_hint == .cold)
1863 try w.writeAll("zig_cold ");
1862
1863 if (fn_val.getFunction(zcu)) |func| {
1864 const func_analysis = func.analysisUnordered(ip);
1865
1866 if (func_analysis.branch_hint == .cold)
1867 try w.writeAll("zig_cold ");
1868
1869 if (kind == .complete and func_analysis.disable_intrinsics or dg.mod.no_builtin)
1870 try w.writeAll("zig_no_builtin ");
1871 }
1872
18641873 if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
18651874
18661875 var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{});
src/codegen/llvm.zig+29-24
......@@ -1447,6 +1447,19 @@ pub const Object = struct {
14471447 try attributes.addFnAttr(.nosanitize_coverage, &o.builder);
14481448 }
14491449
1450 const disable_intrinsics = func_analysis.disable_intrinsics or owner_mod.no_builtin;
1451 if (disable_intrinsics) {
1452 // The intent here is for compiler-rt and libc functions to not generate
1453 // infinite recursion. For example, if we are compiling the memcpy function,
1454 // and llvm detects that the body is equivalent to memcpy, it may replace the
1455 // body of memcpy with a call to memcpy, which would then cause a stack
1456 // overflow instead of performing memcpy.
1457 try attributes.addFnAttr(.{ .string = .{
1458 .kind = try o.builder.string("no-builtins"),
1459 .value = .empty,
1460 } }, &o.builder);
1461 }
1462
14501463 // TODO: disable this if safety is off for the function scope
14511464 const ssp_buf_size = owner_mod.stack_protector;
14521465 if (ssp_buf_size != 0) {
......@@ -1750,6 +1763,7 @@ pub const Object = struct {
17501763 .prev_dbg_line = 0,
17511764 .prev_dbg_column = 0,
17521765 .err_ret_trace = err_ret_trace,
1766 .disable_intrinsics = disable_intrinsics,
17531767 };
17541768 defer fg.deinit();
17551769 deinit_wip = false;
......@@ -3129,17 +3143,6 @@ pub const Object = struct {
31293143 &o.builder,
31303144 );
31313145 }
3132 if (owner_mod.no_builtin) {
3133 // The intent here is for compiler-rt and libc functions to not generate
3134 // infinite recursion. For example, if we are compiling the memcpy function,
3135 // and llvm detects that the body is equivalent to memcpy, it may replace the
3136 // body of memcpy with a call to memcpy, which would then cause a stack
3137 // overflow instead of performing memcpy.
3138 try attributes.addFnAttr(.{ .string = .{
3139 .kind = try o.builder.string("no-builtins"),
3140 .value = .empty,
3141 } }, &o.builder);
3142 }
31433146 if (owner_mod.optimize_mode == .ReleaseSmall) {
31443147 try attributes.addFnAttr(.minsize, &o.builder);
31453148 try attributes.addFnAttr(.optsize, &o.builder);
......@@ -4918,6 +4921,8 @@ pub const FuncGen = struct {
49184921
49194922 sync_scope: Builder.SyncScope,
49204923
4924 disable_intrinsics: bool,
4925
49214926 const Fuzz = struct {
49224927 counters_variable: Builder.Variable.Index,
49234928 pcs: std.ArrayListUnmanaged(Builder.Constant),
......@@ -5443,7 +5448,7 @@ pub const FuncGen = struct {
54435448 var attributes: Builder.FunctionAttributes.Wip = .{};
54445449 defer attributes.deinit(&o.builder);
54455450
5446 if (self.ng.ownerModule().no_builtin) {
5451 if (self.disable_intrinsics) {
54475452 try attributes.addFnAttr(.nobuiltin, &o.builder);
54485453 }
54495454
......@@ -5770,7 +5775,7 @@ pub const FuncGen = struct {
57705775 try o.builder.intValue(.i8, 0xaa),
57715776 len,
57725777 if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,
5773 self.ng.ownerModule().no_builtin,
5778 self.disable_intrinsics,
57745779 );
57755780 const owner_mod = self.ng.ownerModule();
57765781 if (owner_mod.valgrind) {
......@@ -5821,7 +5826,7 @@ pub const FuncGen = struct {
58215826 try o.builder.intValue(.i8, 0xaa),
58225827 len,
58235828 .normal,
5824 self.ng.ownerModule().no_builtin,
5829 self.disable_intrinsics,
58255830 );
58265831 const owner_mod = self.ng.ownerModule();
58275832 if (owner_mod.valgrind) {
......@@ -9735,7 +9740,7 @@ pub const FuncGen = struct {
97359740 if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),
97369741 len,
97379742 if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,
9738 self.ng.ownerModule().no_builtin,
9743 self.disable_intrinsics,
97399744 );
97409745 if (safety and owner_mod.valgrind) {
97419746 try self.valgrindMarkUndef(dest_ptr, len);
......@@ -10057,7 +10062,7 @@ pub const FuncGen = struct {
1005710062 fill_byte,
1005810063 len,
1005910064 access_kind,
10060 self.ng.ownerModule().no_builtin,
10065 self.disable_intrinsics,
1006110066 );
1006210067 }
1006310068 const owner_mod = self.ng.ownerModule();
......@@ -10089,7 +10094,7 @@ pub const FuncGen = struct {
1008910094 fill_byte,
1009010095 len,
1009110096 access_kind,
10092 self.ng.ownerModule().no_builtin,
10097 self.disable_intrinsics,
1009310098 );
1009410099 }
1009510100 return .none;
......@@ -10119,7 +10124,7 @@ pub const FuncGen = struct {
1011910124 fill_byte,
1012010125 len,
1012110126 access_kind,
10122 self.ng.ownerModule().no_builtin,
10127 self.disable_intrinsics,
1012310128 );
1012410129 }
1012510130 return .none;
......@@ -10172,7 +10177,7 @@ pub const FuncGen = struct {
1017210177 elem_abi_align.toLlvm(),
1017310178 try o.builder.intValue(llvm_usize_ty, elem_abi_size),
1017410179 access_kind,
10175 self.ng.ownerModule().no_builtin,
10180 self.disable_intrinsics,
1017610181 );
1017710182 } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align);
1017810183 const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{
......@@ -10206,7 +10211,7 @@ pub const FuncGen = struct {
1020610211 fill_byte,
1020710212 len,
1020810213 access_kind,
10209 self.ng.ownerModule().no_builtin,
10214 self.disable_intrinsics,
1021010215 );
1021110216 _ = try self.wip.br(end_block);
1021210217 self.wip.cursor = .{ .block = end_block };
......@@ -10249,7 +10254,7 @@ pub const FuncGen = struct {
1024910254 src_ptr_ty.ptrAlignment(zcu).toLlvm(),
1025010255 len,
1025110256 access_kind,
10252 self.ng.ownerModule().no_builtin,
10257 self.disable_intrinsics,
1025310258 );
1025410259 _ = try self.wip.br(end_block);
1025510260 self.wip.cursor = .{ .block = end_block };
......@@ -10263,7 +10268,7 @@ pub const FuncGen = struct {
1026310268 src_ptr_ty.ptrAlignment(zcu).toLlvm(),
1026410269 len,
1026510270 access_kind,
10266 self.ng.ownerModule().no_builtin,
10271 self.disable_intrinsics,
1026710272 );
1026810273 return .none;
1026910274 }
......@@ -11397,7 +11402,7 @@ pub const FuncGen = struct {
1139711402 ptr_alignment,
1139811403 try o.builder.intValue(try o.lowerType(Type.usize), size_bytes),
1139911404 access_kind,
11400 fg.ng.ownerModule().no_builtin,
11405 fg.disable_intrinsics,
1140111406 );
1140211407 return result_ptr;
1140311408 }
......@@ -11565,7 +11570,7 @@ pub const FuncGen = struct {
1156511570 elem_ty.abiAlignment(zcu).toLlvm(),
1156611571 try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(zcu)),
1156711572 access_kind,
11568 self.ng.ownerModule().no_builtin,
11573 self.disable_intrinsics,
1156911574 );
1157011575 }
1157111576
src/print_zir.zig+1
......@@ -531,6 +531,7 @@ const Writer = struct {
531531 .frame_address,
532532 .breakpoint,
533533 .disable_instrumentation,
534 .disable_intrinsics,
534535 .c_va_start,
535536 .in_comptime,
536537 .value_placeholder,