pub fn doNotOptimizeAway(val: anytype) void {
if (@inComptime()) return;
if (builtin.zig_backend == .stage2_c and builtin.abi == .msvc) {
_ = @atomicRmw(*const anyopaque, @as(*volatile *const anyopaque, &struct {
var escape: *const anyopaque = undefined;
}.escape), .Xchg, &val, .acq_rel); // TODO: syncscope("singlethreaded")
return;
}
switch (@typeInfo(@TypeOf(val))) {
.void, .null, .comptime_int, .comptime_float => return,
.@"enum" => doNotOptimizeAway(@backingInt(val)),
.bool => doNotOptimizeAway(@intFromBool(val)),
.int => |int| {
// SPIR-V targets do not have registers per se, they have values
// tied to IDs that can be passed to valid instructions. Some
// SPIR-V targets do not define c_long, so we just allow any sized
// integer on these targets
const val_fits_in_gp_register = builtin.target.cpu.arch.isSpirV() or fits: {
const max_gp_register_bits = @bitSizeOf(c_long);
break :fits int.bits <= max_gp_register_bits;
};
if (val_fits_in_gp_register) {
const val2 = @as(
@Int(int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, int.bits))),
val,
);
asm volatile (""
:
: [_] "r" (val2),
);
} else {
doNotOptimizeAway(&val);
}
},
.float => |float| switch (float.bits) {
else => comptime unreachable,
16, 80, 128 => doNotOptimizeAway(&val),
32, 64 => asm volatile (""
:
: [_] "rm" (val),
),
},
.pointer => asm volatile (""
:
: [_] "m" (val),
: .{ .memory = true }),
.array => |array| if (array.len * @sizeOf(array.child) <= 64) {
for (val) |v| doNotOptimizeAway(v);
} else doNotOptimizeAway(&val),
else => doNotOptimizeAway(&val),
}
}
Force an evaluation of the expression; this tries to prevent the compiler from optimizing the computation away even if the result eventually gets discarded.