cbe: implement some float ops

This commit is contained in:
Jacob Young 2022-10-18 22:43:34 -04:00
parent b48417aed2
commit 6921b0a850
3 changed files with 68 additions and 17 deletions

View File

@ -336,6 +336,26 @@ pub const Function = struct {
fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
return f.object.dg.fmtIntLiteral(ty, val);
}
fn renderFloatFnName(f: *Function, fn_name: []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);
const writer = f.object.writer();
if (!is_longdouble and float_bits == 80) {
try writer.writeAll("__");
}
try writer.writeAll(fn_name);
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`.
@ -2076,8 +2096,17 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.sub => try airBinOp (f, inst, " - "),
.mul => try airBinOp (f, inst, " * "),
.div_float, .div_exact => try airBinOp( f, inst, " / "),
.rem => try airBinOp( f, inst, " % "),
.rem => blk: {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
const lhs_ty = f.air.typeOf(bin_op.lhs);
// For binary operations @TypeOf(lhs)==@TypeOf(rhs),
// so we only check one.
break :blk if (lhs_ty.isInt())
try airBinOp(f, inst, " % ")
else
try airBinFloatOp(f, inst, "fmod"); // yes, @rem() => fmod()
},
.div_trunc => blk: {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
const lhs_ty = f.air.typeOf(bin_op.lhs);
@ -2115,8 +2144,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.floor,
.ceil,
.round,
.trunc_float,
=> |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}),
=> |tag| try airUnFloatOp(f, inst, @tagName(tag)),
.trunc_float => try airUnFloatOp(f, inst, "trunc"),
.mul_add => try airMulAdd(f, inst),
@ -4573,12 +4602,45 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(un_op);
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeByte('-');
try writer.writeAll(" = -");
try f.writeCValue(writer, operand);
try writer.writeAll(";\n");
return local;
}
fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !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.renderFloatFnName(fn_name, inst_ty);
try writer.writeByte('(');
try f.writeCValue(writer, operand);
try writer.writeAll(");\n");
return local;
}
fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue {
if (f.liveness.isUnused(inst)) return CValue.none;
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
const writer = f.object.writer();
const inst_ty = f.air.typeOfIndex(inst);
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = ");
try f.renderFloatFnName(fn_name, inst_ty);
try writer.writeByte('(');
try f.writeCValue(writer, lhs);
try writer.writeAll(", ");
try f.writeCValue(writer, rhs);
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;
@ -4588,17 +4650,10 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
const mulend2 = try f.resolveInst(extra.rhs);
const addend = try f.resolveInst(pl_op.operand);
const writer = f.object.writer();
const target = f.object.dg.module.getTarget();
const fn_name = switch (inst_ty.floatBits(target)) {
16, 32 => "fmaf",
64 => "fma",
80 => if (CType.longdouble.sizeInBits(target) == 80) "fmal" else "__fmax",
128 => if (CType.longdouble.sizeInBits(target) == 128) "fmal" else "fmaq",
else => unreachable,
};
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = ");
try writer.print("{s}(", .{fn_name});
try f.renderFloatFnName("fma", inst_ty);
try writer.writeByte('(');
try f.writeCValue(writer, mulend1);
try writer.writeAll(", ");
try f.writeCValue(writer, mulend2);

View File

@ -571,7 +571,6 @@ test "negation f32" {
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 {
@ -593,7 +592,6 @@ test "negation f64" {
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_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
const S = struct {
fn doTheTest() !void {

View File

@ -376,7 +376,6 @@ fn testBinaryNot(x: u16) !void {
}
test "division" {
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_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
@ -1706,7 +1705,6 @@ test "absFloat" {
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 testAbsFloat();
comptime try testAbsFloat();