Skip to content

Commit ecc7634

Browse files
authored
Merge pull request #22154 from alexrp/disable-intrinsics
compiler: Implement `@disableIntrinsics()` builtin function.
2 parents 76558f8 + e11ac02 commit ecc7634

File tree

10 files changed

+107
-28
lines changed

10 files changed

+107
-28
lines changed

lib/std/zig/AstGen.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

60526053
pub 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

12321+
pub 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+
1231612333
pub 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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

6650+
fn 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+
66456667
fn 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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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,

0 commit comments

Comments
 (0)