Skip to content

Commit

Permalink
Merge pull request #16163 from mlugg/feat/builtins-infer-dest-ty
Browse files Browse the repository at this point in the history
Infer destination type of cast builtins using result type
  • Loading branch information
andrewrk committed Jun 24, 2023
2 parents 13853be + 21ac0be commit 146b79a
Show file tree
Hide file tree
Showing 654 changed files with 9,915 additions and 9,611 deletions.
124 changes: 65 additions & 59 deletions doc/langref.html.in

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions lib/compiler_rt/addf3.zig
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,28 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
const significandMask = (@as(Z, 1) << significandBits) - 1;

const absMask = signBit - 1;
const qnanRep = @bitCast(Z, math.nan(T)) | quietBit;
const qnanRep = @as(Z, @bitCast(math.nan(T))) | quietBit;

var aRep = @bitCast(Z, a);
var bRep = @bitCast(Z, b);
var aRep = @as(Z, @bitCast(a));
var bRep = @as(Z, @bitCast(b));
const aAbs = aRep & absMask;
const bAbs = bRep & absMask;

const infRep = @bitCast(Z, math.inf(T));
const infRep = @as(Z, @bitCast(math.inf(T)));

// Detect if a or b is zero, infinity, or NaN.
if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or
bAbs -% @as(Z, 1) >= infRep - @as(Z, 1))
{
// NaN + anything = qNaN
if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit);
if (aAbs > infRep) return @as(T, @bitCast(@as(Z, @bitCast(a)) | quietBit));
// anything + NaN = qNaN
if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit);
if (bAbs > infRep) return @as(T, @bitCast(@as(Z, @bitCast(b)) | quietBit));

if (aAbs == infRep) {
// +/-infinity + -/+infinity = qNaN
if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) {
return @bitCast(T, qnanRep);
if ((@as(Z, @bitCast(a)) ^ @as(Z, @bitCast(b))) == signBit) {
return @as(T, @bitCast(qnanRep));
}
// +/-infinity + anything remaining = +/- infinity
else {
Expand All @@ -60,7 +60,7 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
if (aAbs == 0) {
// but we need to get the sign right for zero + zero
if (bAbs == 0) {
return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b));
return @as(T, @bitCast(@as(Z, @bitCast(a)) & @as(Z, @bitCast(b))));
} else {
return b;
}
Expand All @@ -78,8 +78,8 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
}

// Extract the exponent and significand from the (possibly swapped) a and b.
var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent);
var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent);
var aExponent = @as(i32, @intCast((aRep >> significandBits) & maxExponent));
var bExponent = @as(i32, @intCast((bRep >> significandBits) & maxExponent));
var aSignificand = aRep & significandMask;
var bSignificand = bRep & significandMask;

Expand All @@ -101,25 +101,25 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {

// Shift the significand of b by the difference in exponents, with a sticky
// bottom bit to get rounding correct.
const @"align" = @intCast(u32, aExponent - bExponent);
const @"align" = @as(u32, @intCast(aExponent - bExponent));
if (@"align" != 0) {
if (@"align" < typeWidth) {
const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0;
bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky;
const sticky = if (bSignificand << @as(S, @intCast(typeWidth - @"align")) != 0) @as(Z, 1) else 0;
bSignificand = (bSignificand >> @as(S, @truncate(@"align"))) | sticky;
} else {
bSignificand = 1; // sticky; b is known to be non-zero.
}
}
if (subtraction) {
aSignificand -= bSignificand;
// If a == -b, return +zero.
if (aSignificand == 0) return @bitCast(T, @as(Z, 0));
if (aSignificand == 0) return @as(T, @bitCast(@as(Z, 0)));

// If partial cancellation occured, we need to left-shift the result
// and adjust the exponent:
if (aSignificand < integerBit << 3) {
const shift = @intCast(i32, @clz(aSignificand)) - @intCast(i32, @clz(integerBit << 3));
aSignificand <<= @intCast(S, shift);
const shift = @as(i32, @intCast(@clz(aSignificand))) - @as(i32, @intCast(@clz(integerBit << 3)));
aSignificand <<= @as(S, @intCast(shift));
aExponent -= shift;
}
} else { // addition
Expand All @@ -135,13 +135,13 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
}

// If we have overflowed the type, return +/- infinity:
if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign);
if (aExponent >= maxExponent) return @as(T, @bitCast(infRep | resultSign));

if (aExponent <= 0) {
// Result is denormal; the exponent and round/sticky bits are zero.
// All we need to do is shift the significand and apply the correct sign.
aSignificand >>= @intCast(S, 4 - aExponent);
return @bitCast(T, resultSign | aSignificand);
aSignificand >>= @as(S, @intCast(4 - aExponent));
return @as(T, @bitCast(resultSign | aSignificand));
}

// Low three bits are round, guard, and sticky.
Expand All @@ -151,7 +151,7 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
var result = (aSignificand >> 3) & significandMask;

// Insert the exponent and sign.
result |= @intCast(Z, aExponent) << significandBits;
result |= @as(Z, @intCast(aExponent)) << significandBits;
result |= resultSign;

// Final rounding. The result may overflow to infinity, but that is the
Expand All @@ -164,7 +164,7 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
if ((result >> significandBits) != 0) result |= integerBit;
}

return @bitCast(T, result);
return @as(T, @bitCast(result));
}

test {
Expand Down
46 changes: 23 additions & 23 deletions lib/compiler_rt/addf3_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

const std = @import("std");
const math = std.math;
const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64);
const qnan128 = @as(f128, @bitCast(@as(u128, 0x7fff800000000000) << 64));

const __addtf3 = @import("addtf3.zig").__addtf3;
const __addxf3 = @import("addxf3.zig").__addxf3;
Expand All @@ -14,9 +14,9 @@ const __subtf3 = @import("subtf3.zig").__subtf3;
fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void {
const x = __addtf3(a, b);

const rep = @bitCast(u128, x);
const hi = @intCast(u64, rep >> 64);
const lo = @truncate(u64, rep);
const rep = @as(u128, @bitCast(x));
const hi = @as(u64, @intCast(rep >> 64));
const lo = @as(u64, @truncate(rep));

if (hi == expected_hi and lo == expected_lo) {
return;
Expand All @@ -37,7 +37,7 @@ test "addtf3" {
try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);

// NaN + any = NaN
try test__addtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
try test__addtf3(@as(f128, @bitCast((@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000))), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);

// inf + inf = inf
try test__addtf3(math.inf(f128), math.inf(f128), 0x7fff000000000000, 0x0);
Expand All @@ -53,9 +53,9 @@ test "addtf3" {
fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void {
const x = __subtf3(a, b);

const rep = @bitCast(u128, x);
const hi = @intCast(u64, rep >> 64);
const lo = @truncate(u64, rep);
const rep = @as(u128, @bitCast(x));
const hi = @as(u64, @intCast(rep >> 64));
const lo = @as(u64, @truncate(rep));

if (hi == expected_hi and lo == expected_lo) {
return;
Expand All @@ -77,7 +77,7 @@ test "subtf3" {
try test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);

// NaN + any = NaN
try test__subtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
try test__subtf3(@as(f128, @bitCast((@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000))), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);

// inf - any = inf
try test__subtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0);
Expand All @@ -87,50 +87,50 @@ test "subtf3" {
try test__subtf3(0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x1.234567829a3bcdef5678ade36734p+5, 0xc0041b8af1915166, 0xa44a7bca780a166c);
}

const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1)));
const qnan80 = @as(f80, @bitCast(@as(u80, @bitCast(math.nan(f80))) | (1 << (math.floatFractionalBits(f80) - 1))));

fn test__addxf3(a: f80, b: f80, expected: u80) !void {
const x = __addxf3(a, b);
const rep = @bitCast(u80, x);
const rep = @as(u80, @bitCast(x));

if (rep == expected)
return;

if (math.isNan(@bitCast(f80, expected)) and math.isNan(x))
if (math.isNan(@as(f80, @bitCast(expected))) and math.isNan(x))
return; // We don't currently test NaN payload propagation

return error.TestFailed;
}

test "addxf3" {
// NaN + any = NaN
try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80));
try test__addxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80));
try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80)));
try test__addxf3(@as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80)));

// any + NaN = NaN
try test__addxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80));
try test__addxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80));
try test__addxf3(0x1.23456789abcdefp+5, qnan80, @as(u80, @bitCast(qnan80)));
try test__addxf3(0x1.23456789abcdefp+5, @as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), @as(u80, @bitCast(qnan80)));

// NaN + inf = NaN
try test__addxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80));
try test__addxf3(qnan80, math.inf(f80), @as(u80, @bitCast(qnan80)));

// inf + NaN = NaN
try test__addxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80));
try test__addxf3(math.inf(f80), qnan80, @as(u80, @bitCast(qnan80)));

// inf + inf = inf
try test__addxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80)));
try test__addxf3(math.inf(f80), math.inf(f80), @as(u80, @bitCast(math.inf(f80))));

// inf + -inf = NaN
try test__addxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, qnan80));
try test__addxf3(math.inf(f80), -math.inf(f80), @as(u80, @bitCast(qnan80)));

// -inf + inf = NaN
try test__addxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, qnan80));
try test__addxf3(-math.inf(f80), math.inf(f80), @as(u80, @bitCast(qnan80)));

// inf + any = inf
try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80)));
try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @as(u80, @bitCast(math.inf(f80))));

// any + inf = inf
try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80)));
try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @as(u80, @bitCast(math.inf(f80))));

// any + any
try test__addxf3(0x1.23456789abcdp+5, 0x1.dcba987654321p+5, 0x4005_BFFFFFFFFFFFC400);
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler_rt/arm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,6 @@ pub fn __aeabi_ldivmod() callconv(.Naked) void {
}

pub fn __aeabi_drsub(a: f64, b: f64) callconv(.AAPCS) f64 {
const neg_a = @bitCast(f64, @bitCast(u64, a) ^ (@as(u64, 1) << 63));
const neg_a = @as(f64, @bitCast(@as(u64, @bitCast(a)) ^ (@as(u64, 1) << 63)));
return b + neg_a;
}
6 changes: 3 additions & 3 deletions lib/compiler_rt/atomics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,16 @@ fn wideUpdate(comptime T: type, ptr: *T, val: T, update: anytype) T {

const addr = @intFromPtr(ptr);
const wide_addr = addr & ~(@as(T, smallest_atomic_fetch_exch_size) - 1);
const wide_ptr = @alignCast(smallest_atomic_fetch_exch_size, @ptrFromInt(*WideAtomic, wide_addr));
const wide_ptr: *align(smallest_atomic_fetch_exch_size) WideAtomic = @alignCast(@as(*WideAtomic, @ptrFromInt(wide_addr)));

const inner_offset = addr & (@as(T, smallest_atomic_fetch_exch_size) - 1);
const inner_shift = @intCast(std.math.Log2Int(T), inner_offset * 8);
const inner_shift = @as(std.math.Log2Int(T), @intCast(inner_offset * 8));

const mask = @as(WideAtomic, std.math.maxInt(T)) << inner_shift;

var wide_old = @atomicLoad(WideAtomic, wide_ptr, .SeqCst);
while (true) {
const old = @truncate(T, (wide_old & mask) >> inner_shift);
const old = @as(T, @truncate((wide_old & mask) >> inner_shift));
const new = update(val, old);
const wide_new = wide_old & ~mask | (@as(WideAtomic, new) << inner_shift);
if (@cmpxchgWeak(WideAtomic, wide_ptr, wide_old, wide_new, .SeqCst, .SeqCst)) |new_wide_old| {
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler_rt/aulldiv.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 {
const an = (a ^ s_a) -% s_a;
const bn = (b ^ s_b) -% s_b;

const r = @bitCast(u64, an) / @bitCast(u64, bn);
const r = @as(u64, @bitCast(an)) / @as(u64, @bitCast(bn));
const s = s_a ^ s_b;
return (@bitCast(i64, r) ^ s) -% s;
return (@as(i64, @bitCast(r)) ^ s) -% s;
}

pub fn _aulldiv() callconv(.Naked) void {
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler_rt/aullrem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 {
const an = (a ^ s_a) -% s_a;
const bn = (b ^ s_b) -% s_b;

const r = @bitCast(u64, an) % @bitCast(u64, bn);
const r = @as(u64, @bitCast(an)) % @as(u64, @bitCast(bn));
const s = s_a ^ s_b;
return (@bitCast(i64, r) ^ s) -% s;
return (@as(i64, @bitCast(r)) ^ s) -% s;
}

pub fn _aullrem() callconv(.Naked) void {
Expand Down
16 changes: 8 additions & 8 deletions lib/compiler_rt/ceil.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ comptime {

pub fn __ceilh(x: f16) callconv(.C) f16 {
// TODO: more efficient implementation
return @floatCast(f16, ceilf(x));
return @as(f16, @floatCast(ceilf(x)));
}

pub fn ceilf(x: f32) callconv(.C) f32 {
var u = @bitCast(u32, x);
var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
var u = @as(u32, @bitCast(x));
var e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F;
var m: u32 = undefined;

// TODO: Shouldn't need this explicit check.
Expand All @@ -43,7 +43,7 @@ pub fn ceilf(x: f32) callconv(.C) f32 {
if (e >= 23) {
return x;
} else if (e >= 0) {
m = @as(u32, 0x007FFFFF) >> @intCast(u5, e);
m = @as(u32, 0x007FFFFF) >> @as(u5, @intCast(e));
if (u & m == 0) {
return x;
}
Expand All @@ -52,7 +52,7 @@ pub fn ceilf(x: f32) callconv(.C) f32 {
u += m;
}
u &= ~m;
return @bitCast(f32, u);
return @as(f32, @bitCast(u));
} else {
math.doNotOptimizeAway(x + 0x1.0p120);
if (u >> 31 != 0) {
Expand All @@ -66,7 +66,7 @@ pub fn ceilf(x: f32) callconv(.C) f32 {
pub fn ceil(x: f64) callconv(.C) f64 {
const f64_toint = 1.0 / math.floatEps(f64);

const u = @bitCast(u64, x);
const u = @as(u64, @bitCast(x));
const e = (u >> 52) & 0x7FF;
var y: f64 = undefined;

Expand Down Expand Up @@ -96,13 +96,13 @@ pub fn ceil(x: f64) callconv(.C) f64 {

pub fn __ceilx(x: f80) callconv(.C) f80 {
// TODO: more efficient implementation
return @floatCast(f80, ceilq(x));
return @as(f80, @floatCast(ceilq(x)));
}

pub fn ceilq(x: f128) callconv(.C) f128 {
const f128_toint = 1.0 / math.floatEps(f128);

const u = @bitCast(u128, x);
const u = @as(u128, @bitCast(x));
const e = (u >> 112) & 0x7FFF;
var y: f128 = undefined;

Expand Down
4 changes: 2 additions & 2 deletions lib/compiler_rt/clear_cache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn clear_cache(start: usize, end: usize) callconv(.C) void {
// If CTR_EL0.IDC is set, data cache cleaning to the point of unification
// is not required for instruction to data coherence.
if (((ctr_el0 >> 28) & 0x1) == 0x0) {
const dcache_line_size: usize = @as(usize, 4) << @intCast(u6, (ctr_el0 >> 16) & 15);
const dcache_line_size: usize = @as(usize, 4) << @as(u6, @intCast((ctr_el0 >> 16) & 15));
addr = start & ~(dcache_line_size - 1);
while (addr < end) : (addr += dcache_line_size) {
asm volatile ("dc cvau, %[addr]"
Expand All @@ -115,7 +115,7 @@ fn clear_cache(start: usize, end: usize) callconv(.C) void {
// If CTR_EL0.DIC is set, instruction cache invalidation to the point of
// unification is not required for instruction to data coherence.
if (((ctr_el0 >> 29) & 0x1) == 0x0) {
const icache_line_size: usize = @as(usize, 4) << @intCast(u6, (ctr_el0 >> 0) & 15);
const icache_line_size: usize = @as(usize, 4) << @as(u6, @intCast((ctr_el0 >> 0) & 15));
addr = start & ~(icache_line_size - 1);
while (addr < end) : (addr += icache_line_size) {
asm volatile ("ic ivau, %[addr]"
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler_rt/clzdi2_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const clz = @import("count0bits.zig");
const testing = @import("std").testing;

fn test__clzdi2(a: u64, expected: i64) !void {
var x = @bitCast(i64, a);
var x = @as(i64, @bitCast(a));
var result = clz.__clzdi2(x);
try testing.expectEqual(expected, result);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler_rt/clzsi2_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const testing = @import("std").testing;

fn test__clzsi2(a: u32, expected: i32) !void {
const nakedClzsi2 = clz.__clzsi2;
const actualClzsi2 = @ptrCast(*const fn (a: i32) callconv(.C) i32, &nakedClzsi2);
const x = @bitCast(i32, a);
const actualClzsi2 = @as(*const fn (a: i32) callconv(.C) i32, @ptrCast(&nakedClzsi2));
const x = @as(i32, @bitCast(a));
const result = actualClzsi2(x);
try testing.expectEqual(expected, result);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler_rt/clzti2_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const clz = @import("count0bits.zig");
const testing = @import("std").testing;

fn test__clzti2(a: u128, expected: i64) !void {
var x = @bitCast(i128, a);
var x = @as(i128, @bitCast(a));
var result = clz.__clzti2(x);
try testing.expectEqual(expected, result);
}
Expand Down
Loading

0 comments on commit 146b79a

Please sign in to comment.