Improve and remove duplicate doNotOptimizeAway() implementations (#13790)

* Improve and remove duplicate doNotOptimizeAway() implementations

We currently have two doNotOptimizeAway() implementations, one in
std.math and the other one in std.mem.

Maybe we should deprecate one. In the meantime, the std.math one
now just calls the std.mem one.

In a comptime environment, just ignore the value. Previously,
std.mem.doNotOptimizeAway() did not work at comptime.

If the value fits in a CPU register, just tell the compiler we
need that value to be computed, without clobbering anything else.

Only clobber all possibly escaped memory on pointers or large arrays.

Add tests by the way since we didn't had any (we had, but only
indirect ones).
This commit is contained in:
Frank Denis
2022-12-09 18:22:50 +01:00
committed by GitHub
parent 65f35a76f9
commit c49e4d534f
2 changed files with 70 additions and 12 deletions

View File

@@ -195,13 +195,8 @@ test "approxEqAbs and approxEqRel" {
}
}
pub fn doNotOptimizeAway(value: anytype) void {
// TODO: use @declareSideEffect() when it is available.
// https://github.com/ziglang/zig/issues/6168
const T = @TypeOf(value);
var x: T = undefined;
const p = @ptrCast(*volatile T, &x);
p.* = x;
pub fn doNotOptimizeAway(val: anytype) void {
return mem.doNotOptimizeAway(val);
}
pub fn raiseInvalid() void {

View File

@@ -3559,12 +3559,75 @@ pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T {
/// Force an evaluation of the expression; this tries to prevent
/// the compiler from optimizing the computation away even if the
/// result eventually gets discarded.
// TODO: use @declareSideEffect() when it is available - https://github.com/ziglang/zig/issues/6168
pub fn doNotOptimizeAway(val: anytype) void {
asm volatile (""
:
: [val] "rm" (val),
: "memory"
);
var a: u8 = 0;
if (@typeInfo(@TypeOf(.{a})).Struct.fields[0].is_comptime) return;
const max_gp_register_bits = @bitSizeOf(c_long);
const t = @typeInfo(@TypeOf(val));
switch (t) {
.Void, .Null, .ComptimeInt, .ComptimeFloat => return,
.Enum => doNotOptimizeAway(@enumToInt(val)),
.Bool => doNotOptimizeAway(@boolToInt(val)),
.Int => {
const bits = t.Int.bits;
if (bits <= max_gp_register_bits) {
const val2 = @as(
std.meta.Int(t.Int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))),
val,
);
asm volatile (""
:
: [val2] "r" (val2),
);
} else doNotOptimizeAway(&val);
},
.Float => {
if (t.Float.bits == 32 or t.Float.bits == 64) {
asm volatile (""
:
: [val] "rm" (val),
);
} else doNotOptimizeAway(&val);
},
.Pointer => asm volatile (""
:
: [val] "m" (val),
: "memory"
),
.Array => {
if (t.Array.len * @sizeOf(t.Array.child) <= 64) {
for (val) |v| doNotOptimizeAway(v);
} else doNotOptimizeAway(&val);
},
else => doNotOptimizeAway(&val),
}
}
test "doNotOptimizeAway" {
comptime doNotOptimizeAway("test");
doNotOptimizeAway(null);
doNotOptimizeAway(true);
doNotOptimizeAway(0);
doNotOptimizeAway(0.0);
doNotOptimizeAway(@as(u1, 0));
doNotOptimizeAway(@as(u3, 0));
doNotOptimizeAway(@as(u8, 0));
doNotOptimizeAway(@as(u16, 0));
doNotOptimizeAway(@as(u32, 0));
doNotOptimizeAway(@as(u64, 0));
doNotOptimizeAway(@as(u128, 0));
doNotOptimizeAway(@as(u13, 0));
doNotOptimizeAway(@as(u37, 0));
doNotOptimizeAway(@as(u96, 0));
doNotOptimizeAway(@as(u200, 0));
doNotOptimizeAway(@as(f32, 0.0));
doNotOptimizeAway(@as(f64, 0.0));
doNotOptimizeAway([_]u8{0} ** 4);
doNotOptimizeAway([_]u8{0} ** 100);
doNotOptimizeAway(@as(std.builtin.Endian, .Little));
}
test "alignForward" {