Skip to content

Commit

Permalink
stage2: lower float negation explicitly
Browse files Browse the repository at this point in the history
Rather than lowering float negation as `0.0 - x`.

 * Add AIR instruction for float negation.
 * Add compiler-rt functions for f128, f80 negation

closes ziglang#11853
  • Loading branch information
andrewrk authored and wooster0 committed Jul 24, 2022
1 parent 4a90a9d commit dfb8cf7
Show file tree
Hide file tree
Showing 25 changed files with 237 additions and 57 deletions.
7 changes: 5 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,6 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/multf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulxf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXi2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/os_version_check.zig"
Expand All @@ -623,11 +622,15 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/sincos.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/sqrt.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/stack_probe.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subo.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subsf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subtf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/subxf3.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negsf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negdf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negtf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/negxf2.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/tan.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/trig.zig"
"${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc.zig"
Expand Down
12 changes: 8 additions & 4 deletions lib/compiler_rt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ comptime {
_ = @import("compiler_rt/atomics.zig");

_ = @import("compiler_rt/addf3.zig");
_ = @import("compiler_rt/adddf3.zig");
_ = @import("compiler_rt/addsf3.zig");
_ = @import("compiler_rt/adddf3.zig");
_ = @import("compiler_rt/addtf3.zig");
_ = @import("compiler_rt/addxf3.zig");
_ = @import("compiler_rt/subdf3.zig");

_ = @import("compiler_rt/subsf3.zig");
_ = @import("compiler_rt/subdf3.zig");
_ = @import("compiler_rt/subtf3.zig");
_ = @import("compiler_rt/subxf3.zig");

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

_ = @import("compiler_rt/negsf2.zig");
_ = @import("compiler_rt/negdf2.zig");
_ = @import("compiler_rt/negtf2.zig");
_ = @import("compiler_rt/negxf2.zig");

_ = @import("compiler_rt/comparef.zig");
_ = @import("compiler_rt/cmpsf2.zig");
_ = @import("compiler_rt/cmpdf2.zig");
Expand Down Expand Up @@ -172,8 +178,6 @@ comptime {
_ = @import("compiler_rt/mulo.zig");
_ = @import("compiler_rt/cmp.zig");

_ = @import("compiler_rt/negXf2.zig");

_ = @import("compiler_rt/os_version_check.zig");
_ = @import("compiler_rt/emutls.zig");
_ = @import("compiler_rt/arm.zig");
Expand Down
12 changes: 12 additions & 0 deletions lib/compiler_rt/common.zig
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,15 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn
significand.* <<= @intCast(std.math.Log2Int(Z), shift);
return @as(i32, 1) - shift;
}

pub inline fn fneg(a: anytype) @TypeOf(a) {
const F = @TypeOf(a);
const bits = @typeInfo(F).Float.bits;
const U = @Type(.{ .Int = .{
.signedness = .unsigned,
.bits = bits,
} });
const sign_bit_mask = @as(U, 1) << (bits - 1);
const negated = @bitCast(U, a) ^ sign_bit_mask;
return @bitCast(F, negated);
}
42 changes: 0 additions & 42 deletions lib/compiler_rt/negXf2.zig

This file was deleted.

19 changes: 19 additions & 0 deletions lib/compiler_rt/negdf2.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const common = @import("./common.zig");

pub const panic = common.panic;

comptime {
if (common.want_aeabi) {
@export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = common.linkage });
} else {
@export(__negdf2, .{ .name = "__negdf2", .linkage = common.linkage });
}
}

fn __negdf2(a: f64) callconv(.C) f64 {
return common.fneg(a);
}

fn __aeabi_dneg(a: f64) callconv(.AAPCS) f64 {
return common.fneg(a);
}
19 changes: 19 additions & 0 deletions lib/compiler_rt/negsf2.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const common = @import("./common.zig");

pub const panic = common.panic;

comptime {
if (common.want_aeabi) {
@export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = common.linkage });
} else {
@export(__negsf2, .{ .name = "__negsf2", .linkage = common.linkage });
}
}

fn __negsf2(a: f32) callconv(.C) f32 {
return common.fneg(a);
}

fn __aeabi_fneg(a: f32) callconv(.AAPCS) f32 {
return common.fneg(a);
}
11 changes: 11 additions & 0 deletions lib/compiler_rt/negtf2.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const common = @import("./common.zig");

pub const panic = common.panic;

comptime {
@export(__negtf2, .{ .name = "__negtf2", .linkage = common.linkage });
}

fn __negtf2(a: f128) callconv(.C) f128 {
return common.fneg(a);
}
11 changes: 11 additions & 0 deletions lib/compiler_rt/negxf2.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const common = @import("./common.zig");

pub const panic = common.panic;

comptime {
@export(__negxf2, .{ .name = "__negxf2", .linkage = common.linkage });
}

fn __negxf2(a: f80) callconv(.C) f80 {
return common.fneg(a);
}
2 changes: 0 additions & 2 deletions lib/std/fmt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2225,7 +2225,6 @@ test "float.scientific.precision" {
}

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

test "float.hexadecimal.special" {
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64});
// negative nan is not defined by IEE 754,
// and ARM thus normalizes it to positive nan
Expand Down
1 change: 0 additions & 1 deletion lib/std/math/copysign.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pub fn copysign(magnitude: anytype, sign: @TypeOf(magnitude)) @TypeOf(magnitude)
}

test "math.copysign" {
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
try expect(copysign(@as(T, 1.0), @as(T, 1.0)) == 1.0);
try expect(copysign(@as(T, 2.0), @as(T, -2.0)) == -2.0);
Expand Down
1 change: 0 additions & 1 deletion lib/std/math/signbit.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pub fn signbit(x: anytype) bool {
}

test "math.signbit" {
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
try expect(!signbit(@as(T, 0.0)));
try expect(!signbit(@as(T, 1.0)));
Expand Down
6 changes: 6 additions & 0 deletions src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ pub const Inst = struct {
/// Rounds a floating pointer number to the nearest integer towards zero.
/// Uses the `un_op` field.
trunc_float,
/// Float negation. This affects the sign of zero, inf, and NaN, which is impossible
/// to do with sub. Integers are not allowed and must be represented with sub with
/// LHS of zero.
/// Uses the `un_op` field.
neg,

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

.cmp_lt,
Expand Down
2 changes: 2 additions & 0 deletions src/Liveness.zig
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ pub fn categorizeOperand(
.ceil,
.round,
.trunc_float,
.neg,
.cmp_lt_errors_len,
=> {
const o = air_datas[inst].un_op;
Expand Down Expand Up @@ -834,6 +835,7 @@ fn analyzeInst(
.ceil,
.round,
.trunc_float,
.neg,
.cmp_lt_errors_len,
.set_err_return_trace,
=> {
Expand Down
4 changes: 3 additions & 1 deletion src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10070,12 +10070,14 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}

if (rhs_scalar_ty.isAnyFloat()) {
// We handle comptime negation here to ensure negative zero is represented in the bits.
// We handle float negation here to ensure negative zero is represented in the bits.
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty);
const target = sema.mod.getTarget();
return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
}
try sema.requireRuntimeBlock(block, rhs_src);
return block.addUnOp(.neg, rhs);
}

const lhs = if (rhs_ty.zigTypeTag() == .Vector)
Expand Down
3 changes: 2 additions & 1 deletion src/arch/aarch64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.floor,
.ceil,
.round,
.trunc_float
.trunc_float,
.neg,
=> try self.airUnaryMath(inst),

.add_with_overflow => try self.airOverflow(inst),
Expand Down
1 change: 1 addition & 0 deletions src/arch/arm/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.ceil,
.round,
.trunc_float,
.neg,
=> try self.airUnaryMath(inst),

.add_with_overflow => try self.airOverflow(inst),
Expand Down
1 change: 1 addition & 0 deletions src/arch/riscv64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.ceil,
.round,
.trunc_float,
.neg,
=> try self.airUnaryMath(inst),

.add_with_overflow => try self.airAddWithOverflow(inst),
Expand Down
1 change: 1 addition & 0 deletions src/arch/sparc64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.ceil,
.round,
.trunc_float,
.neg,
=> @panic("TODO try self.airUnaryMath(inst)"),

.add_with_overflow => try self.airAddSubWithOverflow(inst),
Expand Down
1 change: 1 addition & 0 deletions src/arch/wasm/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.log10,
.fabs,
.round,
.neg,

.cmpxchg_weak,
.cmpxchg_strong,
Expand Down
1 change: 1 addition & 0 deletions src/arch/x86_64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.ceil,
.round,
.trunc_float,
.neg,
=> try self.airUnaryMath(inst),

.add_with_overflow => try self.airAddSubShlWithOverflow(inst),
Expand Down
16 changes: 16 additions & 0 deletions src/codegen/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.mul_sat => try airSatOp(f, inst, "muls_"),
.shl_sat => try airSatOp(f, inst, "shls_"),

.neg => try airNeg(f, inst),

.sqrt,
.sin,
.cos,
Expand Down Expand Up @@ -4098,6 +4100,20 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}

fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue {
if (f.liveness.isUnused(inst)) return CValue.none;

const un_op = f.air.instructions.items(.data)[inst].un_op;
const writer = f.object.writer();
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(un_op);
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll("-");
try f.writeCValue(writer, operand);
try writer.writeAll(";\n");
return local;
}

fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
if (f.liveness.isUnused(inst)) return CValue.none;
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
Expand Down
14 changes: 11 additions & 3 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4022,6 +4022,7 @@ pub const FuncGen = struct {
.ceil => try self.airUnaryOp(inst, .ceil),
.round => try self.airUnaryOp(inst, .round),
.trunc_float => try self.airUnaryOp(inst, .trunc),
.neg => try self.airUnaryOp(inst, .neg),

.cmp_eq => try self.airCmp(inst, .eq),
.cmp_gt => try self.airCmp(inst, .gt),
Expand Down Expand Up @@ -6548,13 +6549,14 @@ pub const FuncGen = struct {
fabs,
floor,
fma,
fmax,
fmin,
fmod,
log,
log10,
log2,
fmax,
fmin,
mul,
fmod,
neg,
round,
sin,
sqrt,
Expand Down Expand Up @@ -6587,6 +6589,7 @@ pub const FuncGen = struct {
var fn_name_buf: [64]u8 = undefined;
const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
// Some operations are dedicated LLVM instructions, not available as intrinsics
.neg => return self.builder.buildFNeg(params[0], ""),
.add => return self.builder.buildFAdd(params[0], params[1], ""),
.sub => return self.builder.buildFSub(params[0], params[1], ""),
.mul => return self.builder.buildFMul(params[0], params[1], ""),
Expand All @@ -6598,6 +6601,11 @@ pub const FuncGen = struct {
} else b: {
const float_bits = scalar_ty.floatBits(target);
break :b switch (op) {
.neg => FloatOpStrat{
.libc = std.fmt.bufPrintZ(&fn_name_buf, "__neg{s}f2", .{
compilerRtFloatAbbrev(float_bits),
}) catch unreachable,
},
.add, .sub, .div, .mul => FloatOpStrat{
.libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{
@tagName(op), compilerRtFloatAbbrev(float_bits),
Expand Down
Loading

0 comments on commit dfb8cf7

Please sign in to comment.