cbe: add support for all float literals types

This commit is contained in:
Jacob Young 2022-10-24 23:05:25 -04:00
parent 54326cc554
commit 6021edd7ce
9 changed files with 76 additions and 81 deletions

View File

@ -340,7 +340,7 @@ zig_int_operators(64)
#define zig_int_helpers(w) \
static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \
zig_i##w sign_mask = lhs < zig_as_i##w(0) ? zig_as_i##w(-1) : zig_as_i##w(0); \
zig_i##w sign_mask = lhs < zig_as_i##w(0) ? -zig_as_i##w(1) : zig_as_i##w(0); \
return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \
} \
\
@ -1166,7 +1166,7 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
#define zig_mod_u128 zig_rem_u128
static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) {
zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i8(0) ? zig_as_i128(-1, UINT64_MAX) : zig_as_i128(0, 0);
zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i8(0) ? -zig_as_i128(0, 1) : zig_as_i128(0, 0);
return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask);
}

View File

@ -415,26 +415,6 @@ pub const Function = struct {
},
}
}
fn renderFloatFnName(f: *Function, writer: anytype, operation: []const u8, float_ty: Type) !void {
const target = f.object.dg.module.getTarget();
const float_bits = float_ty.floatBits(target);
const is_longdouble = float_bits == CType.longdouble.sizeInBits(target);
try writer.writeAll("__");
if (is_longdouble or float_bits != 80) {
try writer.writeAll("builtin_");
}
try writer.writeAll(operation);
if (is_longdouble) {
try writer.writeByte('l');
} else switch (float_bits) {
16, 32 => try writer.writeByte('f'),
64 => {},
80 => try writer.writeByte('x'),
128 => try writer.writeByte('q'),
else => unreachable,
}
}
};
/// This data is available when outputting .c code for a `Module`.
@ -674,14 +654,18 @@ pub const DeclGen = struct {
// bool b = 0xaa; evals to true, but memcpy(&b, 0xaa, 1); evals to false.
.Bool => return dg.renderValue(writer, ty, Value.@"false", location),
.Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}),
.Float => switch (ty.tag()) {
.f32 => return writer.print("zig_bitcast_f32_u32({x})", .{
try dg.fmtIntLiteral(Type.u32, val),
}),
.f64 => return writer.print("zig_bitcast_f64_u64({x})", .{
try dg.fmtIntLiteral(Type.u64, val),
}),
else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),
.Float => {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
switch (ty.floatBits(target)) {
16 => return writer.print("{x}f", .{@bitCast(f16, undefPattern(u16))}),
32 => return writer.print("{x}f", .{@bitCast(f32, undefPattern(u32))}),
64 => return writer.print("{x}", .{@bitCast(f64, undefPattern(u64))}),
80 => return writer.print("{x}l", .{@bitCast(f80, undefPattern(u80))}),
128 => return writer.print("{x}l", .{@bitCast(f128, undefPattern(u128))}),
else => unreachable,
}
},
.Pointer => switch (ty.ptrSize()) {
.Slice => {
@ -833,37 +817,41 @@ pub const DeclGen = struct {
else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val)}),
},
.Float => {
if (ty.floatBits(target) <= 64) {
if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) {
// just generate a bit cast (exactly like we do in airBitcast)
switch (ty.tag()) {
.f32 => {
var bitcast_pl = Value.Payload.U64{
.base = .{ .tag = .int_u64 },
.data = @bitCast(u32, val.toFloat(f32)),
};
const bitcast_val = Value.initPayload(&bitcast_pl.base);
return writer.print("zig_bitcast_f32_u32({x})", .{
try dg.fmtIntLiteral(Type.u32, bitcast_val),
});
},
.f64 => {
var bitcast_pl = Value.Payload.U64{
.base = .{ .tag = .int_u64 },
.data = @bitCast(u64, val.toFloat(f64)),
};
const bitcast_val = Value.initPayload(&bitcast_pl.base);
return writer.print("zig_bitcast_f64_u64({x})", .{
try dg.fmtIntLiteral(Type.u64, bitcast_val),
});
},
else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),
}
} else {
return writer.print("{x}", .{val.toFloat(f64)});
}
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
const f128_val = val.toFloat(f128);
if (!std.math.isFinite(f128_val)) {
if (std.math.signbit(f128_val)) try writer.writeByte('-');
const fn_name = if (std.math.isSignalNan(f128_val))
"nans"
else if (std.math.isNan(f128_val))
"nan"
else if (std.math.isInf(f128_val))
"inf"
else
unreachable;
try dg.renderFloatFnName(writer, fn_name, ty);
try writer.writeByte('(');
if (std.math.isNan(f128_val)) switch (ty.floatBits(target)) {
// We only actually need to pass the significant, but it will get
// properly masked anyway, so just pass the whole value.
16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, val.toFloat(f16))}),
32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, val.toFloat(f32))}),
64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, val.toFloat(f64))}),
80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, val.toFloat(f80))}),
128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}),
else => unreachable,
};
return writer.writeByte(')');
} else switch (ty.floatBits(target)) {
16 => return writer.print("{x}f", .{val.toFloat(f16)}),
32 => return writer.print("{x}f", .{val.toFloat(f32)}),
64 => return writer.print("{x}", .{val.toFloat(f64)}),
80 => return writer.print("{x}l", .{val.toFloat(f80)}),
128 => return writer.print("{x}l", .{f128_val}),
else => unreachable,
}
return dg.fail("TODO: C backend: implement lowering large float values", .{});
},
.Pointer => switch (val.tag()) {
.null_value, .zero => {
@ -2053,6 +2041,26 @@ pub const DeclGen = struct {
}
}
fn renderFloatFnName(dg: *DeclGen, writer: anytype, operation: []const u8, float_ty: Type) !void {
const target = dg.module.getTarget();
const float_bits = float_ty.floatBits(target);
const is_longdouble = float_bits == CType.longdouble.sizeInBits(target);
try writer.writeAll("__");
if (is_longdouble or float_bits != 80) {
try writer.writeAll("builtin_");
}
try writer.writeAll(operation);
if (is_longdouble) {
try writer.writeByte('l');
} else switch (float_bits) {
16, 32 => try writer.writeByte('f'),
64 => {},
80 => try writer.writeByte('x'),
128 => try writer.writeByte('q'),
else => unreachable,
}
}
fn fmtIntLiteral(
dg: *DeclGen,
ty: Type,
@ -5169,7 +5177,7 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
const operand = try f.resolveInst(un_op);
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = ");
try f.renderFloatFnName(writer, operation, inst_ty);
try f.object.dg.renderFloatFnName(writer, operation, inst_ty);
try writer.writeByte('(');
try f.writeCValue(writer, operand, .FunctionArgument);
try writer.writeAll(");\n");
@ -5185,7 +5193,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
const rhs = try f.resolveInst(bin_op.rhs);
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = ");
try f.renderFloatFnName(writer, operation, inst_ty);
try f.object.dg.renderFloatFnName(writer, operation, inst_ty);
try writer.writeByte('(');
try f.writeCValue(writer, lhs, .FunctionArgument);
try writer.writeAll(", ");
@ -5205,7 +5213,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = ");
try f.renderFloatFnName(writer, "fma", inst_ty);
try f.object.dg.renderFloatFnName(writer, "fma", inst_ty);
try writer.writeByte('(');
try f.writeCValue(writer, mulend1, .FunctionArgument);
try writer.writeAll(", ");
@ -5342,6 +5350,10 @@ fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) {
return .{ .data = str };
}
fn undefPattern(comptime T: type) T {
return (1 << (@bitSizeOf(T) | 1)) / 3;
}
const FormatIntLiteralContext = struct {
ty: Type,
val: Value,
@ -5379,9 +5391,7 @@ fn formatIntLiteral(
var int_buf: Value.BigIntSpace = undefined;
const int = if (data.val.isUndefDeep()) blk: {
undef_limbs = try allocator.alloc(Limb, BigInt.calcTwosCompLimbCount(int_info.bits));
const undef_pattern: Limb = (1 << (@bitSizeOf(Limb) | 1)) / 3;
std.mem.set(Limb, undef_limbs, undef_pattern);
std.mem.set(Limb, undef_limbs, undefPattern(Limb));
var undef_int = BigInt.Mutable{
.limbs = undef_limbs,

View File

@ -8,7 +8,6 @@ test "issue12891" {
}
test "nan" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
const f = comptime std.math.nan(f64);
var i: usize = 0;

View File

@ -1283,7 +1283,6 @@ fn boolToStr(b: bool) []const u8 {
test "cast f16 to wider types" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
@ -1302,7 +1301,6 @@ test "cast f16 to wider types" {
test "cast f128 to narrower types" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO

View File

@ -147,7 +147,6 @@ fn testSqrt() !void {
test "more @sqrt f16 tests" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
@ -608,7 +607,6 @@ test "negation f80" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
const S = struct {
@ -629,7 +627,6 @@ test "negation f128" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
const S = struct {
@ -709,7 +706,6 @@ test "nan negation f16" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
const nan_comptime = comptime math.nan(f16);
const neg_nan_comptime = -nan_comptime;
@ -729,7 +725,6 @@ test "nan negation f32" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
const nan_comptime = comptime math.nan(f32);
const neg_nan_comptime = -nan_comptime;
@ -749,7 +744,6 @@ test "nan negation f64" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
const nan_comptime = comptime math.nan(f64);
const neg_nan_comptime = -nan_comptime;

View File

@ -1316,7 +1316,6 @@ test "@fabs f80" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
try testFabs(f80, 12.0);
comptime try testFabs(f80, 12.0);
@ -1625,7 +1624,6 @@ test "compare undefined literal with comptime_int" {
}
test "signed zeros are represented properly" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO

View File

@ -44,7 +44,6 @@ fn testMulAdd16() !void {
test "@mulAdd f80" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO

View File

@ -335,7 +335,6 @@ test "pointer sentinel with optional element" {
test "pointer sentinel with +inf" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO

View File

@ -205,7 +205,6 @@ test "initializing anon struct with explicit type" {
}
test "fieldParentPtr of tuple" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
@ -216,7 +215,6 @@ test "fieldParentPtr of tuple" {
}
test "fieldParentPtr of anon struct" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;