Skip to content

Commit 0b63f0e

Browse files
committed
stage2: lower float negation explicitly
Rather than lowering float negation as `0.0 - x`. * Add AIR instruction for float negation. * Add compiler-rt functions for f128, f80 negation closes #11853
1 parent 1b2d58c commit 0b63f0e

25 files changed

+237
-57
lines changed

CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,6 @@ set(ZIG_STAGE2_SOURCES
608608
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/multf3.zig"
609609
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig"
610610
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulxf3.zig"
611-
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXf2.zig"
612611
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXi2.zig"
613612
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig"
614613
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/os_version_check.zig"
@@ -623,11 +622,15 @@ set(ZIG_STAGE2_SOURCES
623622
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/sincos.zig"
624623
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/sqrt.zig"
625624
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/stack_probe.zig"
626-
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig"
627625
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subo.zig"
628626
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subsf3.zig"
627+
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig"
629628
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subtf3.zig"
630629
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subxf3.zig"
630+
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negsf2.zig"
631+
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negdf2.zig"
632+
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negtf2.zig"
633+
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negxf2.zig"
631634
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/tan.zig"
632635
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/trig.zig"
633636
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc.zig"

lib/compiler_rt.zig

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ comptime {
44
_ = @import("compiler_rt/atomics.zig");
55

66
_ = @import("compiler_rt/addf3.zig");
7-
_ = @import("compiler_rt/adddf3.zig");
87
_ = @import("compiler_rt/addsf3.zig");
8+
_ = @import("compiler_rt/adddf3.zig");
99
_ = @import("compiler_rt/addtf3.zig");
1010
_ = @import("compiler_rt/addxf3.zig");
11-
_ = @import("compiler_rt/subdf3.zig");
11+
1212
_ = @import("compiler_rt/subsf3.zig");
13+
_ = @import("compiler_rt/subdf3.zig");
1314
_ = @import("compiler_rt/subtf3.zig");
1415
_ = @import("compiler_rt/subxf3.zig");
1516

@@ -19,6 +20,11 @@ comptime {
1920
_ = @import("compiler_rt/multf3.zig");
2021
_ = @import("compiler_rt/mulxf3.zig");
2122

23+
_ = @import("compiler_rt/negsf2.zig");
24+
_ = @import("compiler_rt/negdf2.zig");
25+
_ = @import("compiler_rt/negtf2.zig");
26+
_ = @import("compiler_rt/negxf2.zig");
27+
2228
_ = @import("compiler_rt/comparef.zig");
2329
_ = @import("compiler_rt/cmpsf2.zig");
2430
_ = @import("compiler_rt/cmpdf2.zig");
@@ -172,8 +178,6 @@ comptime {
172178
_ = @import("compiler_rt/mulo.zig");
173179
_ = @import("compiler_rt/cmp.zig");
174180

175-
_ = @import("compiler_rt/negXf2.zig");
176-
177181
_ = @import("compiler_rt/os_version_check.zig");
178182
_ = @import("compiler_rt/emutls.zig");
179183
_ = @import("compiler_rt/arm.zig");

lib/compiler_rt/common.zig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,15 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn
188188
significand.* <<= @intCast(std.math.Log2Int(Z), shift);
189189
return @as(i32, 1) - shift;
190190
}
191+
192+
pub inline fn fneg(a: anytype) @TypeOf(a) {
193+
const F = @TypeOf(a);
194+
const bits = @typeInfo(F).Float.bits;
195+
const U = @Type(.{ .Int = .{
196+
.signedness = .unsigned,
197+
.bits = bits,
198+
} });
199+
const sign_bit_mask = @as(U, 1) << (bits - 1);
200+
const negated = @bitCast(U, a) ^ sign_bit_mask;
201+
return @bitCast(F, negated);
202+
}

lib/compiler_rt/negXf2.zig

Lines changed: 0 additions & 42 deletions
This file was deleted.

lib/compiler_rt/negdf2.zig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const common = @import("./common.zig");
2+
3+
pub const panic = common.panic;
4+
5+
comptime {
6+
if (common.want_aeabi) {
7+
@export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = common.linkage });
8+
} else {
9+
@export(__negdf2, .{ .name = "__negdf2", .linkage = common.linkage });
10+
}
11+
}
12+
13+
fn __negdf2(a: f64) callconv(.C) f64 {
14+
return common.fneg(a);
15+
}
16+
17+
fn __aeabi_dneg(a: f64) callconv(.AAPCS) f64 {
18+
return common.fneg(a);
19+
}

lib/compiler_rt/negsf2.zig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const common = @import("./common.zig");
2+
3+
pub const panic = common.panic;
4+
5+
comptime {
6+
if (common.want_aeabi) {
7+
@export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = common.linkage });
8+
} else {
9+
@export(__negsf2, .{ .name = "__negsf2", .linkage = common.linkage });
10+
}
11+
}
12+
13+
fn __negsf2(a: f32) callconv(.C) f32 {
14+
return common.fneg(a);
15+
}
16+
17+
fn __aeabi_fneg(a: f32) callconv(.AAPCS) f32 {
18+
return common.fneg(a);
19+
}

lib/compiler_rt/negtf2.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const common = @import("./common.zig");
2+
3+
pub const panic = common.panic;
4+
5+
comptime {
6+
@export(__negtf2, .{ .name = "__negtf2", .linkage = common.linkage });
7+
}
8+
9+
fn __negtf2(a: f128) callconv(.C) f128 {
10+
return common.fneg(a);
11+
}

lib/compiler_rt/negxf2.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const common = @import("./common.zig");
2+
3+
pub const panic = common.panic;
4+
5+
comptime {
6+
@export(__negxf2, .{ .name = "__negxf2", .linkage = common.linkage });
7+
}
8+
9+
fn __negxf2(a: f80) callconv(.C) f80 {
10+
return common.fneg(a);
11+
}

lib/std/fmt.zig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,7 +2225,6 @@ test "float.scientific.precision" {
22252225
}
22262226

22272227
test "float.special" {
2228-
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
22292228
try expectFmt("f64: nan", "f64: {}", .{math.nan_f64});
22302229
// negative nan is not defined by IEE 754,
22312230
// and ARM thus normalizes it to positive nan
@@ -2237,7 +2236,6 @@ test "float.special" {
22372236
}
22382237

22392238
test "float.hexadecimal.special" {
2240-
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
22412239
try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64});
22422240
// negative nan is not defined by IEE 754,
22432241
// and ARM thus normalizes it to positive nan

lib/std/math/copysign.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ pub fn copysign(magnitude: anytype, sign: @TypeOf(magnitude)) @TypeOf(magnitude)
1313
}
1414

1515
test "math.copysign" {
16-
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
1716
inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
1817
try expect(copysign(@as(T, 1.0), @as(T, 1.0)) == 1.0);
1918
try expect(copysign(@as(T, 2.0), @as(T, -2.0)) == -2.0);

lib/std/math/signbit.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ pub fn signbit(x: anytype) bool {
1010
}
1111

1212
test "math.signbit" {
13-
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
1413
inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
1514
try expect(!signbit(@as(T, 0.0)));
1615
try expect(!signbit(@as(T, 1.0)));

src/Air.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ pub const Inst = struct {
288288
/// Rounds a floating pointer number to the nearest integer towards zero.
289289
/// Uses the `un_op` field.
290290
trunc_float,
291+
/// Float negation. This affects the sign of zero, inf, and NaN, which is impossible
292+
/// to do with sub. Integers are not allowed and must be represented with sub with
293+
/// LHS of zero.
294+
/// Uses the `un_op` field.
295+
neg,
291296

292297
/// `<`. Result type is always bool.
293298
/// Uses the `bin_op` field.
@@ -970,6 +975,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
970975
.ceil,
971976
.round,
972977
.trunc_float,
978+
.neg,
973979
=> return air.typeOf(datas[inst].un_op),
974980

975981
.cmp_lt,

src/Liveness.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ pub fn categorizeOperand(
287287
.ceil,
288288
.round,
289289
.trunc_float,
290+
.neg,
290291
.cmp_lt_errors_len,
291292
=> {
292293
const o = air_datas[inst].un_op;
@@ -834,6 +835,7 @@ fn analyzeInst(
834835
.ceil,
835836
.round,
836837
.trunc_float,
838+
.neg,
837839
.cmp_lt_errors_len,
838840
.set_err_return_trace,
839841
=> {

src/Sema.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10070,12 +10070,14 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1007010070
}
1007110071

1007210072
if (rhs_scalar_ty.isAnyFloat()) {
10073-
// We handle comptime negation here to ensure negative zero is represented in the bits.
10073+
// We handle float negation here to ensure negative zero is represented in the bits.
1007410074
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
1007510075
if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty);
1007610076
const target = sema.mod.getTarget();
1007710077
return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
1007810078
}
10079+
try sema.requireRuntimeBlock(block, rhs_src);
10080+
return block.addUnOp(.neg, rhs);
1007910081
}
1008010082

1008110083
const lhs = if (rhs_ty.zigTypeTag() == .Vector)

src/arch/aarch64/CodeGen.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
582582
.floor,
583583
.ceil,
584584
.round,
585-
.trunc_float
585+
.trunc_float,
586+
.neg,
586587
=> try self.airUnaryMath(inst),
587588

588589
.add_with_overflow => try self.airOverflow(inst),

src/arch/arm/CodeGen.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
596596
.ceil,
597597
.round,
598598
.trunc_float,
599+
.neg,
599600
=> try self.airUnaryMath(inst),
600601

601602
.add_with_overflow => try self.airOverflow(inst),

src/arch/riscv64/CodeGen.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
516516
.ceil,
517517
.round,
518518
.trunc_float,
519+
.neg,
519520
=> try self.airUnaryMath(inst),
520521

521522
.add_with_overflow => try self.airAddWithOverflow(inst),

src/arch/sparc64/CodeGen.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
529529
.ceil,
530530
.round,
531531
.trunc_float,
532+
.neg,
532533
=> @panic("TODO try self.airUnaryMath(inst)"),
533534

534535
.add_with_overflow => try self.airAddSubWithOverflow(inst),

src/arch/wasm/CodeGen.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16071607
.log10,
16081608
.fabs,
16091609
.round,
1610+
.neg,
16101611

16111612
.cmpxchg_weak,
16121613
.cmpxchg_strong,

src/arch/x86_64/CodeGen.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
605605
.ceil,
606606
.round,
607607
.trunc_float,
608+
.neg,
608609
=> try self.airUnaryMath(inst),
609610

610611
.add_with_overflow => try self.airAddSubShlWithOverflow(inst),

src/codegen/c.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,6 +1755,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17551755
.mul_sat => try airSatOp(f, inst, "muls_"),
17561756
.shl_sat => try airSatOp(f, inst, "shls_"),
17571757

1758+
.neg => try airNeg(f, inst),
1759+
17581760
.sqrt,
17591761
.sin,
17601762
.cos,
@@ -4098,6 +4100,20 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
40984100
return local;
40994101
}
41004102

4103+
fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue {
4104+
if (f.liveness.isUnused(inst)) return CValue.none;
4105+
4106+
const un_op = f.air.instructions.items(.data)[inst].un_op;
4107+
const writer = f.object.writer();
4108+
const inst_ty = f.air.typeOfIndex(inst);
4109+
const operand = try f.resolveInst(un_op);
4110+
const local = try f.allocLocal(inst_ty, .Const);
4111+
try writer.writeAll("-");
4112+
try f.writeCValue(writer, operand);
4113+
try writer.writeAll(";\n");
4114+
return local;
4115+
}
4116+
41014117
fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
41024118
if (f.liveness.isUnused(inst)) return CValue.none;
41034119
const pl_op = f.air.instructions.items(.data)[inst].pl_op;

src/codegen/llvm.zig

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4022,6 +4022,7 @@ pub const FuncGen = struct {
40224022
.ceil => try self.airUnaryOp(inst, .ceil),
40234023
.round => try self.airUnaryOp(inst, .round),
40244024
.trunc_float => try self.airUnaryOp(inst, .trunc),
4025+
.neg => try self.airUnaryOp(inst, .neg),
40254026

40264027
.cmp_eq => try self.airCmp(inst, .eq),
40274028
.cmp_gt => try self.airCmp(inst, .gt),
@@ -6548,13 +6549,14 @@ pub const FuncGen = struct {
65486549
fabs,
65496550
floor,
65506551
fma,
6552+
fmax,
6553+
fmin,
6554+
fmod,
65516555
log,
65526556
log10,
65536557
log2,
6554-
fmax,
6555-
fmin,
65566558
mul,
6557-
fmod,
6559+
neg,
65586560
round,
65596561
sin,
65606562
sqrt,
@@ -6587,6 +6589,7 @@ pub const FuncGen = struct {
65876589
var fn_name_buf: [64]u8 = undefined;
65886590
const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
65896591
// Some operations are dedicated LLVM instructions, not available as intrinsics
6592+
.neg => return self.builder.buildFNeg(params[0], ""),
65906593
.add => return self.builder.buildFAdd(params[0], params[1], ""),
65916594
.sub => return self.builder.buildFSub(params[0], params[1], ""),
65926595
.mul => return self.builder.buildFMul(params[0], params[1], ""),
@@ -6598,6 +6601,11 @@ pub const FuncGen = struct {
65986601
} else b: {
65996602
const float_bits = scalar_ty.floatBits(target);
66006603
break :b switch (op) {
6604+
.neg => FloatOpStrat{
6605+
.libc = std.fmt.bufPrintZ(&fn_name_buf, "__neg{s}f2", .{
6606+
compilerRtFloatAbbrev(float_bits),
6607+
}) catch unreachable,
6608+
},
66016609
.add, .sub, .div, .mul => FloatOpStrat{
66026610
.libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{
66036611
@tagName(op), compilerRtFloatAbbrev(float_bits),

0 commit comments

Comments
 (0)