| ... | ... | @@ -3470,10 +3470,10 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO |
| 3470 | 3470 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs |
| 3471 | 3471 | return func.cmpOptionals(lhs, rhs, ty, op); |
| 3472 | 3472 | } |
| 3473 | } else if (ty.isAnyFloat()) { |
| 3474 | return func.cmpFloat(ty, lhs, rhs, op); |
| 3473 | 3475 | } else if (isByRef(ty, mod)) { |
| 3474 | 3476 | return func.cmpBigInt(lhs, rhs, ty, op); |
| 3475 | | } else if (ty.isAnyFloat() and ty.floatBits(func.target) == 16) { |
| 3476 | | return func.cmpFloat16(lhs, rhs, op); |
| 3477 | 3477 | } |
| 3478 | 3478 | |
| 3479 | 3479 | // ensure that when we compare pointers, we emit |
| ... | ... | @@ -3505,26 +3505,47 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO |
| 3505 | 3505 | return WValue{ .stack = {} }; |
| 3506 | 3506 | } |
| 3507 | 3507 | |
| 3508 | | /// Compares 16-bit floats |
| 3509 | | /// NOTE: The result value remains on top of the stack. |
| 3510 | | fn cmpFloat16(func: *CodeGen, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue { |
| 3511 | | const opcode: wasm.Opcode = buildOpcode(.{ |
| 3512 | | .op = switch (op) { |
| 3513 | | .lt => .lt, |
| 3514 | | .lte => .le, |
| 3515 | | .eq => .eq, |
| 3516 | | .neq => .ne, |
| 3517 | | .gte => .ge, |
| 3518 | | .gt => .gt, |
| 3508 | /// Compares two floats. |
| 3509 | /// NOTE: Leaves the result of the comparison on top of the stack. |
| 3510 | fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math.CompareOperator) InnerError!WValue { |
| 3511 | const float_bits = ty.floatBits(func.target); |
| 3512 | |
| 3513 | const op: Op = switch (cmp_op) { |
| 3514 | .lt => .lt, |
| 3515 | .lte => .le, |
| 3516 | .eq => .eq, |
| 3517 | .neq => .ne, |
| 3518 | .gte => .ge, |
| 3519 | .gt => .gt, |
| 3520 | }; |
| 3521 | |
| 3522 | switch (float_bits) { |
| 3523 | 16 => { |
| 3524 | _ = try func.fpext(lhs, Type.f16, Type.f32); |
| 3525 | _ = try func.fpext(rhs, Type.f16, Type.f32); |
| 3526 | const opcode = buildOpcode(.{ .op = op, .valtype1 = .f32 }); |
| 3527 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 3528 | return .stack; |
| 3519 | 3529 | }, |
| 3520 | | .valtype1 = .f32, |
| 3521 | | .signedness = .unsigned, |
| 3522 | | }); |
| 3523 | | _ = try func.fpext(lhs, Type.f16, Type.f32); |
| 3524 | | _ = try func.fpext(rhs, Type.f16, Type.f32); |
| 3525 | | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 3530 | 32, 64 => { |
| 3531 | try func.emitWValue(lhs); |
| 3532 | try func.emitWValue(rhs); |
| 3533 | const val_type: wasm.Valtype = if (float_bits == 32) .f32 else .f64; |
| 3534 | const opcode = buildOpcode(.{ .op = op, .valtype1 = val_type }); |
| 3535 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 3536 | return .stack; |
| 3537 | }, |
| 3538 | 80, 128 => { |
| 3539 | var fn_name_buf: [32]u8 = undefined; |
| 3540 | const fn_name = std.fmt.bufPrint(&fn_name_buf, "__{s}{s}f2", .{ |
| 3541 | @tagName(op), target_util.compilerRtFloatAbbrev(float_bits), |
| 3542 | }) catch unreachable; |
| 3526 | 3543 | |
| 3527 | | return WValue{ .stack = {} }; |
| 3544 | const result = try func.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, Type.bool, &.{ lhs, rhs }); |
| 3545 | return func.cmp(result, WValue{ .imm32 = 0 }, Type.i32, cmp_op); |
| 3546 | }, |
| 3547 | else => unreachable, |
| 3548 | } |
| 3528 | 3549 | } |
| 3529 | 3550 | |
| 3530 | 3551 | fn airCmpVector(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |