| ... | ... | @@ -336,6 +336,26 @@ pub const Function = struct { |
| 336 | 336 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { |
| 337 | 337 | return f.object.dg.fmtIntLiteral(ty, val); |
| 338 | 338 | } |
| 339 | |
| 340 | fn renderFloatFnName(f: *Function, fn_name: []const u8, float_ty: Type) !void { |
| 341 | const target = f.object.dg.module.getTarget(); |
| 342 | const float_bits = float_ty.floatBits(target); |
| 343 | const is_longdouble = float_bits == CType.longdouble.sizeInBits(target); |
| 344 | const writer = f.object.writer(); |
| 345 | if (!is_longdouble and float_bits == 80) { |
| 346 | try writer.writeAll("__"); |
| 347 | } |
| 348 | try writer.writeAll(fn_name); |
| 349 | if (is_longdouble) { |
| 350 | try writer.writeByte('l'); |
| 351 | } else switch (float_bits) { |
| 352 | 16, 32 => try writer.writeByte('f'), |
| 353 | 64 => {}, |
| 354 | 80 => try writer.writeByte('x'), |
| 355 | 128 => try writer.writeByte('q'), |
| 356 | else => unreachable, |
| 357 | } |
| 358 | } |
| 339 | 359 | }; |
| 340 | 360 | |
| 341 | 361 | /// 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 |
| 2076 | 2096 | .sub => try airBinOp (f, inst, " - "), |
| 2077 | 2097 | .mul => try airBinOp (f, inst, " * "), |
| 2078 | 2098 | .div_float, .div_exact => try airBinOp( f, inst, " / "), |
| 2079 | | .rem => try airBinOp( f, inst, " % "), |
| 2080 | 2099 | |
| 2100 | .rem => blk: { |
| 2101 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2102 | const lhs_ty = f.air.typeOf(bin_op.lhs); |
| 2103 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 2104 | // so we only check one. |
| 2105 | break :blk if (lhs_ty.isInt()) |
| 2106 | try airBinOp(f, inst, " % ") |
| 2107 | else |
| 2108 | try airBinFloatOp(f, inst, "fmod"); // yes, @rem() => fmod() |
| 2109 | }, |
| 2081 | 2110 | .div_trunc => blk: { |
| 2082 | 2111 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2083 | 2112 | 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 |
| 2115 | 2144 | .floor, |
| 2116 | 2145 | .ceil, |
| 2117 | 2146 | .round, |
| 2118 | | .trunc_float, |
| 2119 | | => |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}), |
| 2147 | => |tag| try airUnFloatOp(f, inst, @tagName(tag)), |
| 2148 | .trunc_float => try airUnFloatOp(f, inst, "trunc"), |
| 2120 | 2149 | |
| 2121 | 2150 | .mul_add => try airMulAdd(f, inst), |
| 2122 | 2151 | |
| ... | ... | @@ -4573,12 +4602,45 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4573 | 4602 | const inst_ty = f.air.typeOfIndex(inst); |
| 4574 | 4603 | const operand = try f.resolveInst(un_op); |
| 4575 | 4604 | const local = try f.allocLocal(inst_ty, .Const); |
| 4576 | | try writer.writeByte('-'); |
| 4605 | try writer.writeAll(" = -"); |
| 4577 | 4606 | try f.writeCValue(writer, operand); |
| 4578 | 4607 | try writer.writeAll(";\n"); |
| 4579 | 4608 | return local; |
| 4580 | 4609 | } |
| 4581 | 4610 | |
| 4611 | fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue { |
| 4612 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4613 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 4614 | const writer = f.object.writer(); |
| 4615 | const inst_ty = f.air.typeOfIndex(inst); |
| 4616 | const operand = try f.resolveInst(un_op); |
| 4617 | const local = try f.allocLocal(inst_ty, .Const); |
| 4618 | try writer.writeAll(" = "); |
| 4619 | try f.renderFloatFnName(fn_name, inst_ty); |
| 4620 | try writer.writeByte('('); |
| 4621 | try f.writeCValue(writer, operand); |
| 4622 | try writer.writeAll(");\n"); |
| 4623 | return local; |
| 4624 | } |
| 4625 | |
| 4626 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue { |
| 4627 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4628 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4629 | const writer = f.object.writer(); |
| 4630 | const inst_ty = f.air.typeOfIndex(inst); |
| 4631 | const lhs = try f.resolveInst(bin_op.lhs); |
| 4632 | const rhs = try f.resolveInst(bin_op.rhs); |
| 4633 | const local = try f.allocLocal(inst_ty, .Const); |
| 4634 | try writer.writeAll(" = "); |
| 4635 | try f.renderFloatFnName(fn_name, inst_ty); |
| 4636 | try writer.writeByte('('); |
| 4637 | try f.writeCValue(writer, lhs); |
| 4638 | try writer.writeAll(", "); |
| 4639 | try f.writeCValue(writer, rhs); |
| 4640 | try writer.writeAll(");\n"); |
| 4641 | return local; |
| 4642 | } |
| 4643 | |
| 4582 | 4644 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4583 | 4645 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4584 | 4646 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| ... | ... | @@ -4588,17 +4650,10 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4588 | 4650 | const mulend2 = try f.resolveInst(extra.rhs); |
| 4589 | 4651 | const addend = try f.resolveInst(pl_op.operand); |
| 4590 | 4652 | const writer = f.object.writer(); |
| 4591 | | const target = f.object.dg.module.getTarget(); |
| 4592 | | const fn_name = switch (inst_ty.floatBits(target)) { |
| 4593 | | 16, 32 => "fmaf", |
| 4594 | | 64 => "fma", |
| 4595 | | 80 => if (CType.longdouble.sizeInBits(target) == 80) "fmal" else "__fmax", |
| 4596 | | 128 => if (CType.longdouble.sizeInBits(target) == 128) "fmal" else "fmaq", |
| 4597 | | else => unreachable, |
| 4598 | | }; |
| 4599 | 4653 | const local = try f.allocLocal(inst_ty, .Const); |
| 4600 | 4654 | try writer.writeAll(" = "); |
| 4601 | | try writer.print("{s}(", .{fn_name}); |
| 4655 | try f.renderFloatFnName("fma", inst_ty); |
| 4656 | try writer.writeByte('('); |
| 4602 | 4657 | try f.writeCValue(writer, mulend1); |
| 4603 | 4658 | try writer.writeAll(", "); |
| 4604 | 4659 | try f.writeCValue(writer, mulend2); |