| ... | @@ -336,6 +336,26 @@ pub const Function = struct { | ... | @@ -336,6 +336,26 @@ pub const Function = struct { |
| 336 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { | 336 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { |
| 337 | return f.object.dg.fmtIntLiteral(ty, val); | 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 | /// This data is available when outputting .c code for a `Module`. | 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,8 +2096,17 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2076 | .sub => try airBinOp (f, inst, " - "), | 2096 | .sub => try airBinOp (f, inst, " - "), |
| 2077 | .mul => try airBinOp (f, inst, " * "), | 2097 | .mul => try airBinOp (f, inst, " * "), |
| 2078 | .div_float, .div_exact => try airBinOp( f, inst, " / "), | 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 | .div_trunc => blk: { | 2110 | .div_trunc => blk: { |
| 2082 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2111 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2083 | const lhs_ty = f.air.typeOf(bin_op.lhs); | 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,8 +2144,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2115 | .floor, | 2144 | .floor, |
| 2116 | .ceil, | 2145 | .ceil, |
| 2117 | .round, | 2146 | .round, |
| 2118 | .trunc_float, | 2147 | => |tag| try airUnFloatOp(f, inst, @tagName(tag)), |
| 2119 | => |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}), | 2148 | .trunc_float => try airUnFloatOp(f, inst, "trunc"), |
| 2120 | | 2149 | |
| 2121 | .mul_add => try airMulAdd(f, inst), | 2150 | .mul_add => try airMulAdd(f, inst), |
| 2122 | | 2151 | |
| ... | @@ -4573,12 +4602,45 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4573,12 +4602,45 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4573 | const inst_ty = f.air.typeOfIndex(inst); | 4602 | const inst_ty = f.air.typeOfIndex(inst); |
| 4574 | const operand = try f.resolveInst(un_op); | 4603 | const operand = try f.resolveInst(un_op); |
| 4575 | const local = try f.allocLocal(inst_ty, .Const); | 4604 | const local = try f.allocLocal(inst_ty, .Const); |
| 4576 | try writer.writeByte('-'); | 4605 | try writer.writeAll(" = -"); |
| 4577 | try f.writeCValue(writer, operand); | 4606 | try f.writeCValue(writer, operand); |
| 4578 | try writer.writeAll(";\n"); | 4607 | try writer.writeAll(";\n"); |
| 4579 | return local; | 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 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { | 4644 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4583 | if (f.liveness.isUnused(inst)) return CValue.none; | 4645 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4584 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 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,17 +4650,10 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4588 | const mulend2 = try f.resolveInst(extra.rhs); | 4650 | const mulend2 = try f.resolveInst(extra.rhs); |
| 4589 | const addend = try f.resolveInst(pl_op.operand); | 4651 | const addend = try f.resolveInst(pl_op.operand); |
| 4590 | const writer = f.object.writer(); | 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 | const local = try f.allocLocal(inst_ty, .Const); | 4653 | const local = try f.allocLocal(inst_ty, .Const); |
| 4600 | try writer.writeAll(" = "); | 4654 | try writer.writeAll(" = "); |
| 4601 | try writer.print("{s}(", .{fn_name}); | 4655 | try f.renderFloatFnName("fma", inst_ty); |
| | 4656 | try writer.writeByte('('); |
| 4602 | try f.writeCValue(writer, mulend1); | 4657 | try f.writeCValue(writer, mulend1); |
| 4603 | try writer.writeAll(", "); | 4658 | try writer.writeAll(", "); |
| 4604 | try f.writeCValue(writer, mulend2); | 4659 | try f.writeCValue(writer, mulend2); |