| author | |
| committer | |
| log | 722d4a11bbba4052558f6f69b7e710d1206f3355 |
| tree | 5c98c05bb228555a7b7e9bf3c71d48538c3b84e4 |
| parent | dd49ed1c642d917af40bf4a0e03d013f40b3903b |
Support for f128, comptime_float, and c_longdouble require improvements
to compiler_rt and will implemented in a later PR. Some of the code in
this commit could be made more generic, for instance `llvm.airSqrt`
could probably be `llvm.airUnaryMath`, but let's cross that
bridge when we get to it.15 files changed, 217 insertions(+), 55 deletions(-)
src/Air.zig+6| ... | @@ -237,6 +237,10 @@ pub const Inst = struct { | ... | @@ -237,6 +237,10 @@ pub const Inst = struct { |
| 237 | /// Uses the `ty_op` field. | 237 | /// Uses the `ty_op` field. |
| 238 | popcount, | 238 | popcount, |
| 239 | 239 | ||
| 240 | /// Computes the square root of a floating point number. | ||
| 241 | /// Uses the `un_op` field. | ||
| 242 | sqrt, | ||
| 243 | |||
| 240 | /// `<`. Result type is always bool. | 244 | /// `<`. Result type is always bool. |
| 241 | /// Uses the `bin_op` field. | 245 | /// Uses the `bin_op` field. |
| 242 | cmp_lt, | 246 | cmp_lt, |
| ... | @@ -749,6 +753,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -749,6 +753,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 749 | .max, | 753 | .max, |
| 750 | => return air.typeOf(datas[inst].bin_op.lhs), | 754 | => return air.typeOf(datas[inst].bin_op.lhs), |
| 751 | 755 | ||
| 756 | .sqrt => return air.typeOf(datas[inst].un_op), | ||
| 757 | |||
| 752 | .cmp_lt, | 758 | .cmp_lt, |
| 753 | .cmp_lte, | 759 | .cmp_lte, |
| 754 | .cmp_eq, | 760 | .cmp_eq, |
src/Liveness.zig+1| ... | @@ -338,6 +338,7 @@ fn analyzeInst( | ... | @@ -338,6 +338,7 @@ fn analyzeInst( |
| 338 | .ret_load, | 338 | .ret_load, |
| 339 | .tag_name, | 339 | .tag_name, |
| 340 | .error_name, | 340 | .error_name, |
| 341 | .sqrt, | ||
| 341 | => { | 342 | => { |
| 342 | const operand = inst_datas[inst].un_op; | 343 | const operand = inst_datas[inst].un_op; |
| 343 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); | 344 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); |
src/Sema.zig+69-15| ... | @@ -745,19 +745,19 @@ fn analyzeBodyInner( | ... | @@ -745,19 +745,19 @@ fn analyzeBodyInner( |
| 745 | .clz => try sema.zirClzCtz(block, inst, .clz, Value.clz), | 745 | .clz => try sema.zirClzCtz(block, inst, .clz, Value.clz), |
| 746 | .ctz => try sema.zirClzCtz(block, inst, .ctz, Value.ctz), | 746 | .ctz => try sema.zirClzCtz(block, inst, .ctz, Value.ctz), |
| 747 | 747 | ||
| 748 | .sqrt => try sema.zirUnaryMath(block, inst), | 748 | .sqrt => try sema.zirUnaryMath(block, inst, .sqrt), |
| 749 | .sin => try sema.zirUnaryMath(block, inst), | 749 | .sin => try sema.zirUnaryMath(block, inst, .sin), |
| 750 | .cos => try sema.zirUnaryMath(block, inst), | 750 | .cos => try sema.zirUnaryMath(block, inst, .cos), |
| 751 | .exp => try sema.zirUnaryMath(block, inst), | 751 | .exp => try sema.zirUnaryMath(block, inst, .exp), |
| 752 | .exp2 => try sema.zirUnaryMath(block, inst), | 752 | .exp2 => try sema.zirUnaryMath(block, inst, .exp2), |
| 753 | .log => try sema.zirUnaryMath(block, inst), | 753 | .log => try sema.zirUnaryMath(block, inst, .log), |
| 754 | .log2 => try sema.zirUnaryMath(block, inst), | 754 | .log2 => try sema.zirUnaryMath(block, inst, .log2), |
| 755 | .log10 => try sema.zirUnaryMath(block, inst), | 755 | .log10 => try sema.zirUnaryMath(block, inst, .log10), |
| 756 | .fabs => try sema.zirUnaryMath(block, inst), | 756 | .fabs => try sema.zirUnaryMath(block, inst, .fabs), |
| 757 | .floor => try sema.zirUnaryMath(block, inst), | 757 | .floor => try sema.zirUnaryMath(block, inst, .floor), |
| 758 | .ceil => try sema.zirUnaryMath(block, inst), | 758 | .ceil => try sema.zirUnaryMath(block, inst, .ceil), |
| 759 | .trunc => try sema.zirUnaryMath(block, inst), | 759 | .trunc => try sema.zirUnaryMath(block, inst, .trunc), |
| 760 | .round => try sema.zirUnaryMath(block, inst), | 760 | .round => try sema.zirUnaryMath(block, inst, .round), |
| 761 | 761 | ||
| 762 | .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent), | 762 | .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent), |
| 763 | .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), | 763 | .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), |
| ... | @@ -11010,10 +11010,64 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -11010,10 +11010,64 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 11010 | return block.addUnOp(.error_name, operand); | 11010 | return block.addUnOp(.error_name, operand); |
| 11011 | } | 11011 | } |
| 11012 | 11012 | ||
| 11013 | fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 11013 | fn zirUnaryMath( |
| 11014 | sema: *Sema, | ||
| 11015 | block: *Block, | ||
| 11016 | inst: Zir.Inst.Index, | ||
| 11017 | zir_tag: Zir.Inst.Tag, | ||
| 11018 | ) CompileError!Air.Inst.Ref { | ||
| 11019 | const tracy = trace(@src()); | ||
| 11020 | defer tracy.end(); | ||
| 11021 | |||
| 11014 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 11022 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 11015 | const src = inst_data.src(); | 11023 | const src = inst_data.src(); |
| 11016 | return sema.fail(block, src, "TODO: Sema.zirUnaryMath", .{}); | 11024 | const operand = sema.resolveInst(inst_data.operand); |
| 11025 | const operand_ty = sema.typeOf(operand); | ||
| 11026 | const operand_zig_ty_tag = operand_ty.zigTypeTag(); | ||
| 11027 | |||
| 11028 | const is_float = operand_zig_ty_tag == .Float or operand_zig_ty_tag == .ComptimeFloat; | ||
| 11029 | if (!is_float) { | ||
| 11030 | return sema.fail(block, src, "expected float type, found '{s}'", .{@tagName(operand_zig_ty_tag)}); | ||
| 11031 | } | ||
| 11032 | |||
| 11033 | switch (zir_tag) { | ||
| 11034 | .sqrt => { | ||
| 11035 | switch (operand_ty.tag()) { | ||
| 11036 | .f128, | ||
| 11037 | .comptime_float, | ||
| 11038 | .c_longdouble, | ||
| 11039 | => |t| return sema.fail(block, src, "TODO implement @sqrt for type '{s}'", .{@tagName(t)}), | ||
| 11040 | else => {}, | ||
| 11041 | } | ||
| 11042 | |||
| 11043 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand); | ||
| 11044 | if (maybe_operand_val) |val| { | ||
| 11045 | if (val.isUndef()) | ||
| 11046 | return sema.addConstUndef(operand_ty); | ||
| 11047 | const result_val = try val.sqrt(operand_ty, sema.arena); | ||
| 11048 | return sema.addConstant(operand_ty, result_val); | ||
| 11049 | } | ||
| 11050 | |||
| 11051 | try sema.requireRuntimeBlock(block, src); | ||
| 11052 | return block.addUnOp(.sqrt, operand); | ||
| 11053 | }, | ||
| 11054 | |||
| 11055 | .sin, | ||
| 11056 | .cos, | ||
| 11057 | .exp, | ||
| 11058 | .exp2, | ||
| 11059 | .log, | ||
| 11060 | .log2, | ||
| 11061 | .log10, | ||
| 11062 | .fabs, | ||
| 11063 | .floor, | ||
| 11064 | .ceil, | ||
| 11065 | .trunc, | ||
| 11066 | .round, | ||
| 11067 | => return sema.fail(block, src, "TODO: implement zirUnaryMath for ZIR tag '{s}'", .{@tagName(zir_tag)}), | ||
| 11068 | |||
| 11069 | else => unreachable, | ||
| 11070 | } | ||
| 11017 | } | 11071 | } |
| 11018 | 11072 | ||
| 11019 | fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 11073 | fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
src/arch/aarch64/CodeGen.zig+11| ... | @@ -528,6 +528,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -528,6 +528,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 528 | .max => try self.airMax(inst), | 528 | .max => try self.airMax(inst), |
| 529 | .slice => try self.airSlice(inst), | 529 | .slice => try self.airSlice(inst), |
| 530 | 530 | ||
| 531 | .sqrt => try self.airUnaryMath(inst), | ||
| 532 | |||
| 531 | .add_with_overflow => try self.airAddWithOverflow(inst), | 533 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 532 | .sub_with_overflow => try self.airSubWithOverflow(inst), | 534 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 533 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 535 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| ... | @@ -1223,6 +1225,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1223,6 +1225,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 1223 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1225 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1224 | } | 1226 | } |
| 1225 | 1227 | ||
| 1228 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1229 | const un_op = self.air.instructions.items(.data)[inst].un_op; | ||
| 1230 | const result: MCValue = if (self.liveness.isUnused(inst)) | ||
| 1231 | .dead | ||
| 1232 | else | ||
| 1233 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); | ||
| 1234 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | ||
| 1235 | } | ||
| 1236 | |||
| 1226 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { | 1237 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { |
| 1227 | if (!self.liveness.operandDies(inst, op_index)) | 1238 | if (!self.liveness.operandDies(inst, op_index)) |
| 1228 | return false; | 1239 | return false; |
src/arch/arm/CodeGen.zig+11| ... | @@ -520,6 +520,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -520,6 +520,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 520 | .max => try self.airMax(inst), | 520 | .max => try self.airMax(inst), |
| 521 | .slice => try self.airSlice(inst), | 521 | .slice => try self.airSlice(inst), |
| 522 | 522 | ||
| 523 | .sqrt => try self.airUnaryMath(inst), | ||
| 524 | |||
| 523 | .add_with_overflow => try self.airAddWithOverflow(inst), | 525 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 524 | .sub_with_overflow => try self.airSubWithOverflow(inst), | 526 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 525 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 527 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| ... | @@ -1377,6 +1379,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1377,6 +1379,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 1377 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1379 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1378 | } | 1380 | } |
| 1379 | 1381 | ||
| 1382 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1383 | const un_op = self.air.instructions.items(.data)[inst].un_op; | ||
| 1384 | const result: MCValue = if (self.liveness.isUnused(inst)) | ||
| 1385 | .dead | ||
| 1386 | else | ||
| 1387 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); | ||
| 1388 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | ||
| 1389 | } | ||
| 1390 | |||
| 1380 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { | 1391 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { |
| 1381 | if (!self.liveness.operandDies(inst, op_index)) | 1392 | if (!self.liveness.operandDies(inst, op_index)) |
| 1382 | return false; | 1393 | return false; |
src/arch/riscv64/CodeGen.zig+11| ... | @@ -507,6 +507,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -507,6 +507,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 507 | .max => try self.airMax(inst), | 507 | .max => try self.airMax(inst), |
| 508 | .slice => try self.airSlice(inst), | 508 | .slice => try self.airSlice(inst), |
| 509 | 509 | ||
| 510 | .sqrt => try self.airUnaryMath(inst), | ||
| 511 | |||
| 510 | .add_with_overflow => try self.airAddWithOverflow(inst), | 512 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 511 | .sub_with_overflow => try self.airSubWithOverflow(inst), | 513 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 512 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 514 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| ... | @@ -1166,6 +1168,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1166,6 +1168,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 1166 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1168 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1167 | } | 1169 | } |
| 1168 | 1170 | ||
| 1171 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1172 | const un_op = self.air.instructions.items(.data)[inst].un_op; | ||
| 1173 | const result: MCValue = if (self.liveness.isUnused(inst)) | ||
| 1174 | .dead | ||
| 1175 | else | ||
| 1176 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); | ||
| 1177 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | ||
| 1178 | } | ||
| 1179 | |||
| 1169 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { | 1180 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { |
| 1170 | if (!self.liveness.operandDies(inst, op_index)) | 1181 | if (!self.liveness.operandDies(inst, op_index)) |
| 1171 | return false; | 1182 | return false; |
src/arch/wasm/CodeGen.zig+2| ... | @@ -1681,6 +1681,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1681,6 +1681,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1681 | .unwrap_errunion_payload_ptr, | 1681 | .unwrap_errunion_payload_ptr, |
| 1682 | .unwrap_errunion_err_ptr, | 1682 | .unwrap_errunion_err_ptr, |
| 1683 | 1683 | ||
| 1684 | .sqrt, | ||
| 1685 | |||
| 1684 | .ptr_slice_len_ptr, | 1686 | .ptr_slice_len_ptr, |
| 1685 | .ptr_slice_ptr_ptr, | 1687 | .ptr_slice_ptr_ptr, |
| 1686 | .int_to_float, | 1688 | .int_to_float, |
src/arch/x86_64/CodeGen.zig+11| ... | @@ -599,6 +599,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -599,6 +599,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 599 | .max => try self.airMax(inst), | 599 | .max => try self.airMax(inst), |
| 600 | .slice => try self.airSlice(inst), | 600 | .slice => try self.airSlice(inst), |
| 601 | 601 | ||
| 602 | .sqrt => try self.airUnaryMath(inst), | ||
| 603 | |||
| 602 | .add_with_overflow => try self.airAddWithOverflow(inst), | 604 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 603 | .sub_with_overflow => try self.airSubWithOverflow(inst), | 605 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 604 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 606 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| ... | @@ -1578,6 +1580,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1578,6 +1580,15 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 1578 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1580 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1579 | } | 1581 | } |
| 1580 | 1582 | ||
| 1583 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1584 | const un_op = self.air.instructions.items(.data)[inst].un_op; | ||
| 1585 | const result: MCValue = if (self.liveness.isUnused(inst)) | ||
| 1586 | .dead | ||
| 1587 | else | ||
| 1588 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); | ||
| 1589 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | ||
| 1590 | } | ||
| 1591 | |||
| 1581 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { | 1592 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { |
| 1582 | if (!self.liveness.operandDies(inst, op_index)) | 1593 | if (!self.liveness.operandDies(inst, op_index)) |
| 1583 | return false; | 1594 | return false; |
src/codegen/c.zig+8| ... | @@ -1446,6 +1446,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -1446,6 +1446,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1446 | .mul_sat => try airSatOp(f, inst, "muls_"), | 1446 | .mul_sat => try airSatOp(f, inst, "muls_"), |
| 1447 | .shl_sat => try airSatOp(f, inst, "shls_"), | 1447 | .shl_sat => try airSatOp(f, inst, "shls_"), |
| 1448 | 1448 | ||
| 1449 | .sqrt => try airSqrt(f, inst), | ||
| 1450 | |||
| 1449 | .add_with_overflow => try airAddWithOverflow(f, inst), | 1451 | .add_with_overflow => try airAddWithOverflow(f, inst), |
| 1450 | .sub_with_overflow => try airSubWithOverflow(f, inst), | 1452 | .sub_with_overflow => try airSubWithOverflow(f, inst), |
| 1451 | .mul_with_overflow => try airMulWithOverflow(f, inst), | 1453 | .mul_with_overflow => try airMulWithOverflow(f, inst), |
| ... | @@ -3393,6 +3395,12 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3393,6 +3395,12 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3393 | return CValue.none; | 3395 | return CValue.none; |
| 3394 | } | 3396 | } |
| 3395 | 3397 | ||
| 3398 | fn airSqrt(f: *Function, inst: Air.Inst.Index) !CValue { | ||
| 3399 | _ = f; | ||
| 3400 | _ = inst; | ||
| 3401 | return f.fail("TODO: C backend: implement sqrt", .{}); | ||
| 3402 | } | ||
| 3403 | |||
| 3396 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { | 3404 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { |
| 3397 | return switch (order) { | 3405 | return switch (order) { |
| 3398 | .Unordered => "memory_order_relaxed", | 3406 | .Unordered => "memory_order_relaxed", |
src/codegen/llvm.zig+16| ... | @@ -2050,6 +2050,8 @@ pub const FuncGen = struct { | ... | @@ -2050,6 +2050,8 @@ pub const FuncGen = struct { |
| 2050 | .shr => try self.airShr(inst, false), | 2050 | .shr => try self.airShr(inst, false), |
| 2051 | .shr_exact => try self.airShr(inst, true), | 2051 | .shr_exact => try self.airShr(inst, true), |
| 2052 | 2052 | ||
| 2053 | .sqrt => try self.airSqrt(inst), | ||
| 2054 | |||
| 2053 | .cmp_eq => try self.airCmp(inst, .eq), | 2055 | .cmp_eq => try self.airCmp(inst, .eq), |
| 2054 | .cmp_gt => try self.airCmp(inst, .gt), | 2056 | .cmp_gt => try self.airCmp(inst, .gt), |
| 2055 | .cmp_gte => try self.airCmp(inst, .gte), | 2057 | .cmp_gte => try self.airCmp(inst, .gte), |
| ... | @@ -4211,6 +4213,20 @@ pub const FuncGen = struct { | ... | @@ -4211,6 +4213,20 @@ pub const FuncGen = struct { |
| 4211 | } | 4213 | } |
| 4212 | } | 4214 | } |
| 4213 | 4215 | ||
| 4216 | fn airSqrt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | ||
| 4217 | if (self.liveness.isUnused(inst)) return null; | ||
| 4218 | |||
| 4219 | const un_op = self.air.instructions.items(.data)[inst].un_op; | ||
| 4220 | const operand = try self.resolveInst(un_op); | ||
| 4221 | const operand_ty = self.air.typeOf(un_op); | ||
| 4222 | |||
| 4223 | const operand_llvm_ty = try self.dg.llvmType(operand_ty); | ||
| 4224 | const fn_val = self.getIntrinsic("llvm.sqrt", &.{operand_llvm_ty}); | ||
| 4225 | const params = [_]*const llvm.Value{operand}; | ||
| 4226 | |||
| 4227 | return self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, ""); | ||
| 4228 | } | ||
| 4229 | |||
| 4214 | fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, prefix: [*:0]const u8) !?*const llvm.Value { | 4230 | fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, prefix: [*:0]const u8) !?*const llvm.Value { |
| 4215 | if (self.liveness.isUnused(inst)) return null; | 4231 | if (self.liveness.isUnused(inst)) return null; |
| 4216 | 4232 |
src/print_air.zig+1| ... | @@ -158,6 +158,7 @@ const Writer = struct { | ... | @@ -158,6 +158,7 @@ const Writer = struct { |
| 158 | .ret_load, | 158 | .ret_load, |
| 159 | .tag_name, | 159 | .tag_name, |
| 160 | .error_name, | 160 | .error_name, |
| 161 | .sqrt, | ||
| 161 | => try w.writeUnOp(s, inst), | 162 | => try w.writeUnOp(s, inst), |
| 162 | 163 | ||
| 163 | .breakpoint, | 164 | .breakpoint, |
src/value.zig+22| ... | @@ -3265,6 +3265,28 @@ pub const Value = extern union { | ... | @@ -3265,6 +3265,28 @@ pub const Value = extern union { |
| 3265 | } | 3265 | } |
| 3266 | } | 3266 | } |
| 3267 | 3267 | ||
| 3268 | pub fn sqrt(val: Value, float_type: Type, arena: Allocator) !Value { | ||
| 3269 | switch (float_type.tag()) { | ||
| 3270 | .f16 => { | ||
| 3271 | const f = val.toFloat(f16); | ||
| 3272 | return Value.Tag.float_16.create(arena, @sqrt(f)); | ||
| 3273 | }, | ||
| 3274 | .f32 => { | ||
| 3275 | const f = val.toFloat(f32); | ||
| 3276 | return Value.Tag.float_32.create(arena, @sqrt(f)); | ||
| 3277 | }, | ||
| 3278 | .f64 => { | ||
| 3279 | const f = val.toFloat(f64); | ||
| 3280 | return Value.Tag.float_64.create(arena, @sqrt(f)); | ||
| 3281 | }, | ||
| 3282 | |||
| 3283 | // TODO: implement @sqrt for these types | ||
| 3284 | .f128, .comptime_float, .c_longdouble => unreachable, | ||
| 3285 | |||
| 3286 | else => unreachable, | ||
| 3287 | } | ||
| 3288 | } | ||
| 3289 | |||
| 3268 | /// This type is not copyable since it may contain pointers to its inner data. | 3290 | /// This type is not copyable since it may contain pointers to its inner data. |
| 3269 | pub const Payload = struct { | 3291 | pub const Payload = struct { |
| 3270 | tag: Tag, | 3292 | tag: Tag, |
test/behavior/floatop.zig+42| ... | @@ -72,3 +72,45 @@ test "negative f128 floatToInt at compile-time" { | ... | @@ -72,3 +72,45 @@ test "negative f128 floatToInt at compile-time" { |
| 72 | var b = @floatToInt(i64, a); | 72 | var b = @floatToInt(i64, a); |
| 73 | try expect(@as(i64, -2) == b); | 73 | try expect(@as(i64, -2) == b); |
| 74 | } | 74 | } |
| 75 | |||
| 76 | test "@sqrt" { | ||
| 77 | comptime try testSqrt(); | ||
| 78 | try testSqrt(); | ||
| 79 | } | ||
| 80 | |||
| 81 | fn testSqrt() !void { | ||
| 82 | { | ||
| 83 | var a: f16 = 4; | ||
| 84 | try expect(@sqrt(a) == 2); | ||
| 85 | } | ||
| 86 | { | ||
| 87 | var a: f32 = 9; | ||
| 88 | try expect(@sqrt(a) == 3); | ||
| 89 | var b: f32 = 1.1; | ||
| 90 | try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon)); | ||
| 91 | } | ||
| 92 | { | ||
| 93 | var a: f64 = 25; | ||
| 94 | try expect(@sqrt(a) == 5); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | test "more @sqrt f16 tests" { | ||
| 99 | // TODO these are not all passing at comptime | ||
| 100 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 101 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 2.0)), 1.414214, epsilon)); | ||
| 102 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 3.6)), 1.897367, epsilon)); | ||
| 103 | try expect(@sqrt(@as(f16, 4.0)) == 2.0); | ||
| 104 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 7.539840)), 2.745877, epsilon)); | ||
| 105 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 19.230934)), 4.385309, epsilon)); | ||
| 106 | try expect(@sqrt(@as(f16, 64.0)) == 8.0); | ||
| 107 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 64.1)), 8.006248, epsilon)); | ||
| 108 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 8942.230469)), 94.563370, epsilon)); | ||
| 109 | |||
| 110 | // special cases | ||
| 111 | try expect(math.isPositiveInf(@sqrt(@as(f16, math.inf(f16))))); | ||
| 112 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 113 | try expect(@sqrt(@as(f16, -0.0)) == -0.0); | ||
| 114 | try expect(math.isNan(@sqrt(@as(f16, -1.0)))); | ||
| 115 | try expect(math.isNan(@sqrt(@as(f16, math.nan(f16))))); | ||
| 116 | } |
test/behavior/floatop_stage1.zig-34| ... | @@ -14,20 +14,6 @@ test "@sqrt" { | ... | @@ -14,20 +14,6 @@ test "@sqrt" { |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | fn testSqrt() !void { | 16 | fn testSqrt() !void { |
| 17 | { | ||
| 18 | var a: f16 = 4; | ||
| 19 | try expect(@sqrt(a) == 2); | ||
| 20 | } | ||
| 21 | { | ||
| 22 | var a: f32 = 9; | ||
| 23 | try expect(@sqrt(a) == 3); | ||
| 24 | var b: f32 = 1.1; | ||
| 25 | try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon)); | ||
| 26 | } | ||
| 27 | { | ||
| 28 | var a: f64 = 25; | ||
| 29 | try expect(@sqrt(a) == 5); | ||
| 30 | } | ||
| 31 | if (has_f80_rt) { | 17 | if (has_f80_rt) { |
| 32 | var a: f80 = 25; | 18 | var a: f80 = 25; |
| 33 | try expect(@sqrt(a) == 5); | 19 | try expect(@sqrt(a) == 5); |
| ... | @@ -51,26 +37,6 @@ fn testSqrt() !void { | ... | @@ -51,26 +37,6 @@ fn testSqrt() !void { |
| 51 | } | 37 | } |
| 52 | } | 38 | } |
| 53 | 39 | ||
| 54 | test "more @sqrt f16 tests" { | ||
| 55 | // TODO these are not all passing at comptime | ||
| 56 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 57 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 2.0)), 1.414214, epsilon)); | ||
| 58 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 3.6)), 1.897367, epsilon)); | ||
| 59 | try expect(@sqrt(@as(f16, 4.0)) == 2.0); | ||
| 60 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 7.539840)), 2.745877, epsilon)); | ||
| 61 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 19.230934)), 4.385309, epsilon)); | ||
| 62 | try expect(@sqrt(@as(f16, 64.0)) == 8.0); | ||
| 63 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 64.1)), 8.006248, epsilon)); | ||
| 64 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 8942.230469)), 94.563370, epsilon)); | ||
| 65 | |||
| 66 | // special cases | ||
| 67 | try expect(math.isPositiveInf(@sqrt(@as(f16, math.inf(f16))))); | ||
| 68 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 69 | try expect(@sqrt(@as(f16, -0.0)) == -0.0); | ||
| 70 | try expect(math.isNan(@sqrt(@as(f16, -1.0)))); | ||
| 71 | try expect(math.isNan(@sqrt(@as(f16, math.nan(f16))))); | ||
| 72 | } | ||
| 73 | |||
| 74 | test "@sin" { | 40 | test "@sin" { |
| 75 | comptime try testSin(); | 41 | comptime try testSin(); |
| 76 | try testSin(); | 42 | try testSin(); |
test/behavior/math.zig+6-6| ... | @@ -792,8 +792,6 @@ fn remdiv(comptime T: type) !void { | ... | @@ -792,8 +792,6 @@ fn remdiv(comptime T: type) !void { |
| 792 | } | 792 | } |
| 793 | 793 | ||
| 794 | test "@sqrt" { | 794 | test "@sqrt" { |
| 795 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 796 | |||
| 797 | try testSqrt(f64, 12.0); | 795 | try testSqrt(f64, 12.0); |
| 798 | comptime try testSqrt(f64, 12.0); | 796 | comptime try testSqrt(f64, 12.0); |
| 799 | try testSqrt(f32, 13.0); | 797 | try testSqrt(f32, 13.0); |
| ... | @@ -801,10 +799,12 @@ test "@sqrt" { | ... | @@ -801,10 +799,12 @@ test "@sqrt" { |
| 801 | try testSqrt(f16, 13.0); | 799 | try testSqrt(f16, 13.0); |
| 802 | comptime try testSqrt(f16, 13.0); | 800 | comptime try testSqrt(f16, 13.0); |
| 803 | 801 | ||
| 804 | const x = 14.0; | 802 | if (builtin.zig_backend == .stage1) { |
| 805 | const y = x * x; | 803 | const x = 14.0; |
| 806 | const z = @sqrt(y); | 804 | const y = x * x; |
| 807 | comptime try expect(z == x); | 805 | const z = @sqrt(y); |
| 806 | comptime try expect(z == x); | ||
| 807 | } | ||
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | fn testSqrt(comptime T: type, x: T) !void { | 810 | fn testSqrt(comptime T: type, x: T) !void { |