Commit 6921b0a850

Jacob Young <jacobly0@users.noreply.github.com>
2022-10-19 04:43:34
cbe: implement some float ops
1 parent b48417a
Changed files (3)
src
codegen
test
src/codegen/c.zig
@@ -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);
test/behavior/floatop.zig
@@ -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 {
test/behavior/math.zig
@@ -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();