aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-06 15:23:21 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-06 16:11:39 -0700
commit71b8760d3b145c92dc6e331aefff7dac5cabebeb (patch)
tree66b92748616634b689eb5c984f143042132d5e6c /src/codegen/c.zig
parent6637335981f7179b449fced78cfd4052b1618051 (diff)
downloadzig-71b8760d3b145c92dc6e331aefff7dac5cabebeb.tar.gz
zig-71b8760d3b145c92dc6e331aefff7dac5cabebeb.zip
stage2: rework `@mulAdd`
* mul_add AIR instruction: use `pl_op` instead of `ty_pl`. The type is always the same as the operand; no need to waste bytes redundantly storing the type. * AstGen: use coerced_ty for all the operands except for one which we use to communicate the type. * Sema: use the correct source location for requireRuntimeBlock in handling of `@mulAdd`. * native backends: handle liveness even for the functions that are TODO. * C backend: implement `@mulAdd`. It lowers to libc calls. * LLVM backend: make `@mulAdd` handle all float types. - improved fptrunc and fpext to handle f80 with compiler-rt calls. * Value.mulAdd: handle all float types and use the `@mulAdd` builtin. * behavior tests: revert the changes to testing `@mulAdd`. These changes broke the test coverage, making it only tested at compile-time. Improved f80 support: * std.math.fma handles f80 * move fma functions from freestanding libc to compiler-rt - add __fmax and fmal - make __fmax and fmaq only exported when they don't alias fmal. - make their linkage weak just like the rest of compiler-rt symbols. * removed `longDoubleIsF128` and replaced it with `longDoubleIs` which takes a type as a parameter. The implementation is now more accurate and handles more targets. Similarly, in stage2 the function CTypes.sizeInBits is more accurate for long double for more targets.
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig32
1 files changed, 31 insertions, 1 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index e24ff0a6b0..2a10a8094a 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -16,6 +16,7 @@ const trace = @import("../tracy.zig").trace;
const LazySrcLoc = Module.LazySrcLoc;
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
+const CType = @import("../type.zig").CType;
const Mutability = enum { Const, Mut };
const BigIntConst = std.math.big.int.Const;
@@ -1635,7 +1636,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.trunc_float,
=> |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}),
- .mul_add => return f.fail("TODO: C backend: implement @mulAdd", .{}),
+ .mul_add => try airMulAdd(f, inst),
.add_with_overflow => try airAddWithOverflow(f, inst),
.sub_with_overflow => try airSubWithOverflow(f, inst),
@@ -3623,6 +3624,35 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
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;
+ const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
+ const inst_ty = f.air.typeOfIndex(inst);
+ const mulend1 = try f.resolveInst(extra.lhs);
+ 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.writeCValue(writer, mulend1);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, mulend2);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, addend);
+ try writer.writeAll(");\n");
+ return local;
+}
+
fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
return switch (order) {
.Unordered => "memory_order_relaxed",