Our previous implementation of unwind infrastructure was somewhat complex and brittle: it parsed generated instructions in order to reverse-engineer unwind info from prologues. It also relied on some fragile linkage to communicate instruction-layout information that VCode was not designed to provide. A much simpler, more reliable, and easier-to-reason-about approach is to embed unwind directives as pseudo-instructions in the prologue as we generate it. That way, we can say what we mean and just emit it directly. The usual reasoning that leads to the reverse-engineering approach is that metadata is hard to keep in sync across optimization passes; but here, (i) prologues are generated at the very end of the pipeline, and (ii) if we ever do a post-prologue-gen optimization, we can treat unwind directives as black boxes with unknown side-effects, just as we do for some other pseudo-instructions today. It turns out that it was easier to just build this for both x64 and aarch64 (since they share a factored-out ABI implementation), and wire up the platform-specific unwind-info generation for Windows and SystemV. Now we have simpler unwind on all platforms and we can delete the old unwind infra as soon as we remove the old backend. There were a few consequences to supporting Fastcall unwind in particular that led to a refactor of the common ABI. Windows only supports naming clobbered-register save locations within 240 bytes of the frame-pointer register, whatever one chooses that to be (RSP or RBP). We had previously saved clobbers below the fixed frame (and below nominal-SP). The 240-byte range has to include the old RBP too, so we're forced to place clobbers at the top of the frame, just below saved RBP/RIP. This is fine; we always keep a frame pointer anyway because we use it to refer to stack args. It does mean that offsets of fixed-frame slots (spillslots, stackslots) from RBP are no longer known before we do regalloc, so if we ever want to index these off of RBP rather than nominal-SP because we add support for `alloca` (dynamic frame growth), then we'll need a "nominal-BP" mode that is resolved after regalloc and clobber-save code is generated. I added a comment to this effect in `abi_impl.rs`. The above refactor touched both x64 and aarch64 because of shared code. This had a further effect in that the old aarch64 prologue generation subtracted from `sp` once to allocate space, then used stores to `[sp, offset]` to save clobbers. Unfortunately the offset only has 7-bit range, so if there are enough clobbered registers (and there can be -- aarch64 has 384 bytes of registers; at least one unit test hits this) the stores/loads will be out-of-range. I really don't want to synthesize large-offset sequences here; better to go back to the simpler pre-index/post-index `stp r1, r2, [sp, #-16]` form that works just like a "push". It's likely not much worse microarchitecturally (dependence chain on SP, but oh well) and it actually saves an instruction if there's no other frame to allocate. As a further advantage, it's much simpler to understand; simpler is usually better. This PR adds the new backend on Windows to CI as well.
817 lines
16 KiB
Plaintext
817 lines
16 KiB
Plaintext
test compile
|
|
set unwind_info=false
|
|
target aarch64
|
|
|
|
function %f1(f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32):
|
|
v2 = fadd v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fadd s0, s0, s1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f2(f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64):
|
|
v2 = fadd v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fadd d0, d0, d1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f3(f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32):
|
|
v2 = fsub v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fsub s0, s0, s1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f4(f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64):
|
|
v2 = fsub v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fsub d0, d0, d1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f5(f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32):
|
|
v2 = fmul v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmul s0, s0, s1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f6(f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64):
|
|
v2 = fmul v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmul d0, d0, d1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f7(f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32):
|
|
v2 = fdiv v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fdiv s0, s0, s1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f8(f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64):
|
|
v2 = fdiv v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fdiv d0, d0, d1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f9(f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32):
|
|
v2 = fmin v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmin s0, s0, s1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f10(f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64):
|
|
v2 = fmin v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmin d0, d0, d1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f11(f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32):
|
|
v2 = fmax v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmax s0, s0, s1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f12(f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64):
|
|
v2 = fmax v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmax d0, d0, d1
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f13(f32) -> f32 {
|
|
block0(v0: f32):
|
|
v1 = sqrt v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fsqrt s0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f15(f64) -> f64 {
|
|
block0(v0: f64):
|
|
v1 = sqrt v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fsqrt d0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f16(f32) -> f32 {
|
|
block0(v0: f32):
|
|
v1 = fabs v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fabs s0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f17(f64) -> f64 {
|
|
block0(v0: f64):
|
|
v1 = fabs v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fabs d0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f18(f32) -> f32 {
|
|
block0(v0: f32):
|
|
v1 = fneg v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fneg s0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f19(f64) -> f64 {
|
|
block0(v0: f64):
|
|
v1 = fneg v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fneg d0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f20(f32) -> f64 {
|
|
block0(v0: f32):
|
|
v1 = fpromote.f64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcvt d0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f21(f64) -> f32 {
|
|
block0(v0: f64):
|
|
v1 = fdemote.f32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcvt s0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f22(f32) -> f32 {
|
|
block0(v0: f32):
|
|
v1 = ceil v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintp s0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f22(f64) -> f64 {
|
|
block0(v0: f64):
|
|
v1 = ceil v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintp d0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f23(f32) -> f32 {
|
|
block0(v0: f32):
|
|
v1 = floor v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintm s0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f24(f64) -> f64 {
|
|
block0(v0: f64):
|
|
v1 = floor v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintm d0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f25(f32) -> f32 {
|
|
block0(v0: f32):
|
|
v1 = trunc v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintz s0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f26(f64) -> f64 {
|
|
block0(v0: f64):
|
|
v1 = trunc v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintz d0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f27(f32) -> f32 {
|
|
block0(v0: f32):
|
|
v1 = nearest v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintn s0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f28(f64) -> f64 {
|
|
block0(v0: f64):
|
|
v1 = nearest v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: frintn d0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f29(f32, f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32, v2: f32):
|
|
v3 = fma v0, v1, v2
|
|
return v3
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmadd s0, s0, s1, s2
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f30(f64, f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64, v2: f64):
|
|
v3 = fma v0, v1, v2
|
|
return v3
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fmadd d0, d0, d1, d2
|
|
|
|
function %f31(f32, f32) -> f32 {
|
|
block0(v0: f32, v1: f32):
|
|
v2 = fcopysign v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ushr v1.2s, v1.2s, #31
|
|
; nextln: sli v0.2s, v1.2s, #31
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f32(f64, f64) -> f64 {
|
|
block0(v0: f64, v1: f64):
|
|
v2 = fcopysign v0, v1
|
|
return v2
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ushr d1, d1, #63
|
|
; nextln: sli d0, d1, #63
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f33(f32) -> i32 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_uint.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp s0, s0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: movz x0, #49024, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.gt 8 ; udf
|
|
; nextln: movz x0, #20352, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzu w0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f34(f32) -> i32 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_sint.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp s0, s0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: movz x0, #52992, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.ge 8 ; udf
|
|
; nextln: movz x0, #20224, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzs w0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f35(f32) -> i64 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_uint.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp s0, s0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: movz x0, #49024, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.gt 8 ; udf
|
|
; nextln: movz x0, #24448, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzu x0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f36(f32) -> i64 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_sint.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp s0, s0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: movz x0, #57088, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.ge 8 ; udf
|
|
; nextln: movz x0, #24320, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp s0, s1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzs x0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f37(f64) -> i32 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_uint.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp d0, d0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: movz x0, #49136, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.gt 8 ; udf
|
|
; nextln: movz x0, #16880, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzu w0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f38(f64) -> i32 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_sint.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp d0, d0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -2147483649
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.gt 8 ; udf
|
|
; nextln: movz x0, #16864, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzs w0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f39(f64) -> i64 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_uint.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp d0, d0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: movz x0, #49136, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.gt 8 ; udf
|
|
; nextln: movz x0, #17392, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzu x0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f40(f64) -> i64 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_sint.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: fcmp d0, d0
|
|
; nextln: b.vc 8 ; udf
|
|
; nextln: movz x0, #50144, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.ge 8 ; udf
|
|
; nextln: movz x0, #17376, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fcmp d0, d1
|
|
; nextln: b.mi 8 ; udf
|
|
; nextln: fcvtzs x0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f41(i32) -> f32 {
|
|
block0(v0: i32):
|
|
v1 = fcvt_from_uint.f32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ucvtf s0, w0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f42(i32) -> f32 {
|
|
block0(v0: i32):
|
|
v1 = fcvt_from_sint.f32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: scvtf s0, w0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f43(i64) -> f32 {
|
|
block0(v0: i64):
|
|
v1 = fcvt_from_uint.f32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ucvtf s0, x0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f44(i64) -> f32 {
|
|
block0(v0: i64):
|
|
v1 = fcvt_from_sint.f32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: scvtf s0, x0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f45(i32) -> f64 {
|
|
block0(v0: i32):
|
|
v1 = fcvt_from_uint.f64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ucvtf d0, w0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f46(i32) -> f64 {
|
|
block0(v0: i32):
|
|
v1 = fcvt_from_sint.f64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: scvtf d0, w0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f47(i64) -> f64 {
|
|
block0(v0: i64):
|
|
v1 = fcvt_from_uint.f64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ucvtf d0, x0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f48(i64) -> f64 {
|
|
block0(v0: i64):
|
|
v1 = fcvt_from_sint.f64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: scvtf d0, x0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f49(f32) -> i32 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_uint_sat.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: movz x0, #20352, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fmin s2, s0, s1
|
|
; nextln: movi v1.2s, #0
|
|
; nextln: fmax s2, s2, s1
|
|
; nextln: fcmp s0, s0
|
|
; nextln: fcsel s0, s1, s2, ne
|
|
; nextln: fcvtzu w0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f50(f32) -> i32 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_sint_sat.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: movz x0, #20224, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fmin s1, s0, s1
|
|
; nextln: movz x0, #52992, LSL #16
|
|
; nextln: fmov d2, x0
|
|
; nextln: fmax s1, s1, s2
|
|
; nextln: movi v2.2s, #0
|
|
; nextln: fcmp s0, s0
|
|
; nextln: fcsel s0, s2, s1, ne
|
|
; nextln: fcvtzs w0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f51(f32) -> i64 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_uint_sat.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: movz x0, #24448, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fmin s2, s0, s1
|
|
; nextln: movi v1.2s, #0
|
|
; nextln: fmax s2, s2, s1
|
|
; nextln: fcmp s0, s0
|
|
; nextln: fcsel s0, s1, s2, ne
|
|
; nextln: fcvtzu x0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f52(f32) -> i64 {
|
|
block0(v0: f32):
|
|
v1 = fcvt_to_sint_sat.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: movz x0, #24320, LSL #16
|
|
; nextln: fmov d1, x0
|
|
; nextln: fmin s1, s0, s1
|
|
; nextln: movz x0, #57088, LSL #16
|
|
; nextln: fmov d2, x0
|
|
; nextln: fmax s1, s1, s2
|
|
; nextln: movi v2.2s, #0
|
|
; nextln: fcmp s0, s0
|
|
; nextln: fcsel s0, s2, s1, ne
|
|
; nextln: fcvtzs x0, s0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f53(f64) -> i32 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_uint_sat.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 4294967295
|
|
; nextln: fmin d2, d0, d1
|
|
; nextln: movi v1.2s, #0
|
|
; nextln: fmax d2, d2, d1
|
|
; nextln: fcmp d0, d0
|
|
; nextln: fcsel d0, d1, d2, ne
|
|
; nextln: fcvtzu w0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f54(f64) -> i32 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_sint_sat.i32 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 2147483647
|
|
; nextln: fmin d1, d0, d1
|
|
; nextln: movz x0, #49632, LSL #48
|
|
; nextln: fmov d2, x0
|
|
; nextln: fmax d1, d1, d2
|
|
; nextln: movi v2.2s, #0
|
|
; nextln: fcmp d0, d0
|
|
; nextln: fcsel d0, d2, d1, ne
|
|
; nextln: fcvtzs w0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f55(f64) -> i64 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_uint_sat.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: movz x0, #17392, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fmin d2, d0, d1
|
|
; nextln: movi v1.2s, #0
|
|
; nextln: fmax d2, d2, d1
|
|
; nextln: fcmp d0, d0
|
|
; nextln: fcsel d0, d1, d2, ne
|
|
; nextln: fcvtzu x0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|
|
|
|
function %f56(f64) -> i64 {
|
|
block0(v0: f64):
|
|
v1 = fcvt_to_sint_sat.i64 v0
|
|
return v1
|
|
}
|
|
|
|
; check: stp fp, lr, [sp, #-16]!
|
|
; nextln: mov fp, sp
|
|
; nextln: movz x0, #17376, LSL #48
|
|
; nextln: fmov d1, x0
|
|
; nextln: fmin d1, d0, d1
|
|
; nextln: movz x0, #50144, LSL #48
|
|
; nextln: fmov d2, x0
|
|
; nextln: fmax d1, d1, d2
|
|
; nextln: movi v2.2s, #0
|
|
; nextln: fcmp d0, d0
|
|
; nextln: fcsel d0, d2, d1, ne
|
|
; nextln: fcvtzs x0, d0
|
|
; nextln: ldp fp, lr, [sp], #16
|
|
; nextln: ret
|