Dan Gohman e665e781dc
[SelectionDAG] Use the nuw flag when expanding loads. (#119288)
When expanding a load into two loads, use nuw for the add that computes
the offset from the base of the second load, because the original load
doesn't straddle the address space.

It turns out there's already a dedicated helper function for doing this,
`getObjectPtrOffset`.

This is in target-independent code, however in practice it only seems to
affact WebAssembly code, because WebAssembly load and store
instructions' constant offsets don't perform wrapping, so constant
folding often depends on the nuw flag being present.

This was noticed in the development of #119204.
2024-12-10 06:28:09 -08:00

724 lines
26 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
; Test that basic 128-bit integer operations assemble as expected.
target triple = "wasm32-unknown-unknown"
declare i128 @llvm.ctlz.i128(i128, i1)
declare i128 @llvm.cttz.i128(i128, i1)
declare i128 @llvm.ctpop.i128(i128)
define i128 @add128(i128 %x, i128 %y) {
; CHECK-LABEL: add128:
; CHECK: .functype add128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push8=, 0
; CHECK-NEXT: local.get $push7=, 1
; CHECK-NEXT: local.get $push6=, 3
; CHECK-NEXT: i64.add $push5=, $pop7, $pop6
; CHECK-NEXT: local.tee $push4=, 3, $pop5
; CHECK-NEXT: i64.store 0($pop8), $pop4
; CHECK-NEXT: local.get $push13=, 0
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 4
; CHECK-NEXT: i64.add $push0=, $pop10, $pop9
; CHECK-NEXT: local.get $push12=, 3
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: i64.lt_u $push1=, $pop12, $pop11
; CHECK-NEXT: i64.extend_i32_u $push2=, $pop1
; CHECK-NEXT: i64.add $push3=, $pop0, $pop2
; CHECK-NEXT: i64.store 8($pop13), $pop3
; CHECK-NEXT: return
%a = add i128 %x, %y
ret i128 %a
}
define i128 @sub128(i128 %x, i128 %y) {
; CHECK-LABEL: sub128:
; CHECK: .functype sub128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push7=, 0
; CHECK-NEXT: local.get $push6=, 1
; CHECK-NEXT: local.get $push5=, 3
; CHECK-NEXT: i64.sub $push0=, $pop6, $pop5
; CHECK-NEXT: i64.store 0($pop7), $pop0
; CHECK-NEXT: local.get $push12=, 0
; CHECK-NEXT: local.get $push9=, 2
; CHECK-NEXT: local.get $push8=, 4
; CHECK-NEXT: i64.sub $push1=, $pop9, $pop8
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 3
; CHECK-NEXT: i64.lt_u $push2=, $pop11, $pop10
; CHECK-NEXT: i64.extend_i32_u $push3=, $pop2
; CHECK-NEXT: i64.sub $push4=, $pop1, $pop3
; CHECK-NEXT: i64.store 8($pop12), $pop4
; CHECK-NEXT: return
%a = sub i128 %x, %y
ret i128 %a
}
define i128 @mul128(i128 %x, i128 %y) {
; CHECK-LABEL: mul128:
; CHECK: .functype mul128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push2=, __stack_pointer
; CHECK-NEXT: i32.const $push3=, 16
; CHECK-NEXT: i32.sub $push7=, $pop2, $pop3
; CHECK-NEXT: local.tee $push6=, 5, $pop7
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: local.get $push8=, 4
; CHECK-NEXT: call __multi3, $pop12, $pop11, $pop10, $pop9, $pop8
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push0=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop0
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push1=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop1
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.add $push5=, $pop17, $pop4
; CHECK-NEXT: global.set __stack_pointer, $pop5
; CHECK-NEXT: return
%a = mul i128 %x, %y
ret i128 %a
}
define i128 @sdiv128(i128 %x, i128 %y) {
; CHECK-LABEL: sdiv128:
; CHECK: .functype sdiv128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push2=, __stack_pointer
; CHECK-NEXT: i32.const $push3=, 16
; CHECK-NEXT: i32.sub $push7=, $pop2, $pop3
; CHECK-NEXT: local.tee $push6=, 5, $pop7
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: local.get $push8=, 4
; CHECK-NEXT: call __divti3, $pop12, $pop11, $pop10, $pop9, $pop8
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push0=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop0
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push1=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop1
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.add $push5=, $pop17, $pop4
; CHECK-NEXT: global.set __stack_pointer, $pop5
; CHECK-NEXT: return
%a = sdiv i128 %x, %y
ret i128 %a
}
define i128 @udiv128(i128 %x, i128 %y) {
; CHECK-LABEL: udiv128:
; CHECK: .functype udiv128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push2=, __stack_pointer
; CHECK-NEXT: i32.const $push3=, 16
; CHECK-NEXT: i32.sub $push7=, $pop2, $pop3
; CHECK-NEXT: local.tee $push6=, 5, $pop7
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: local.get $push8=, 4
; CHECK-NEXT: call __udivti3, $pop12, $pop11, $pop10, $pop9, $pop8
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push0=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop0
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push1=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop1
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.add $push5=, $pop17, $pop4
; CHECK-NEXT: global.set __stack_pointer, $pop5
; CHECK-NEXT: return
%a = udiv i128 %x, %y
ret i128 %a
}
define i128 @srem128(i128 %x, i128 %y) {
; CHECK-LABEL: srem128:
; CHECK: .functype srem128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push2=, __stack_pointer
; CHECK-NEXT: i32.const $push3=, 16
; CHECK-NEXT: i32.sub $push7=, $pop2, $pop3
; CHECK-NEXT: local.tee $push6=, 5, $pop7
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: local.get $push8=, 4
; CHECK-NEXT: call __modti3, $pop12, $pop11, $pop10, $pop9, $pop8
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push0=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop0
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push1=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop1
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.add $push5=, $pop17, $pop4
; CHECK-NEXT: global.set __stack_pointer, $pop5
; CHECK-NEXT: return
%a = srem i128 %x, %y
ret i128 %a
}
define i128 @urem128(i128 %x, i128 %y) {
; CHECK-LABEL: urem128:
; CHECK: .functype urem128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push2=, __stack_pointer
; CHECK-NEXT: i32.const $push3=, 16
; CHECK-NEXT: i32.sub $push7=, $pop2, $pop3
; CHECK-NEXT: local.tee $push6=, 5, $pop7
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: local.get $push8=, 4
; CHECK-NEXT: call __umodti3, $pop12, $pop11, $pop10, $pop9, $pop8
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push0=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop0
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push1=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop1
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.add $push5=, $pop17, $pop4
; CHECK-NEXT: global.set __stack_pointer, $pop5
; CHECK-NEXT: return
%a = urem i128 %x, %y
ret i128 %a
}
define i128 @and128(i128 %x, i128 %y) {
; CHECK-LABEL: and128:
; CHECK: .functype and128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push4=, 0
; CHECK-NEXT: local.get $push3=, 2
; CHECK-NEXT: local.get $push2=, 4
; CHECK-NEXT: i64.and $push0=, $pop3, $pop2
; CHECK-NEXT: i64.store 8($pop4), $pop0
; CHECK-NEXT: local.get $push7=, 0
; CHECK-NEXT: local.get $push6=, 1
; CHECK-NEXT: local.get $push5=, 3
; CHECK-NEXT: i64.and $push1=, $pop6, $pop5
; CHECK-NEXT: i64.store 0($pop7), $pop1
; CHECK-NEXT: return
%a = and i128 %x, %y
ret i128 %a
}
define i128 @or128(i128 %x, i128 %y) {
; CHECK-LABEL: or128:
; CHECK: .functype or128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push4=, 0
; CHECK-NEXT: local.get $push3=, 2
; CHECK-NEXT: local.get $push2=, 4
; CHECK-NEXT: i64.or $push0=, $pop3, $pop2
; CHECK-NEXT: i64.store 8($pop4), $pop0
; CHECK-NEXT: local.get $push7=, 0
; CHECK-NEXT: local.get $push6=, 1
; CHECK-NEXT: local.get $push5=, 3
; CHECK-NEXT: i64.or $push1=, $pop6, $pop5
; CHECK-NEXT: i64.store 0($pop7), $pop1
; CHECK-NEXT: return
%a = or i128 %x, %y
ret i128 %a
}
define i128 @xor128(i128 %x, i128 %y) {
; CHECK-LABEL: xor128:
; CHECK: .functype xor128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push4=, 0
; CHECK-NEXT: local.get $push3=, 2
; CHECK-NEXT: local.get $push2=, 4
; CHECK-NEXT: i64.xor $push0=, $pop3, $pop2
; CHECK-NEXT: i64.store 8($pop4), $pop0
; CHECK-NEXT: local.get $push7=, 0
; CHECK-NEXT: local.get $push6=, 1
; CHECK-NEXT: local.get $push5=, 3
; CHECK-NEXT: i64.xor $push1=, $pop6, $pop5
; CHECK-NEXT: i64.store 0($pop7), $pop1
; CHECK-NEXT: return
%a = xor i128 %x, %y
ret i128 %a
}
define i128 @shl128(i128 %x, i128 %y) {
; CHECK-LABEL: shl128:
; CHECK: .functype shl128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push3=, __stack_pointer
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.sub $push8=, $pop3, $pop4
; CHECK-NEXT: local.tee $push7=, 5, $pop8
; CHECK-NEXT: global.set __stack_pointer, $pop7
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: i32.wrap_i64 $push0=, $pop9
; CHECK-NEXT: call __ashlti3, $pop12, $pop11, $pop10, $pop0
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push1=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop1
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push2=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop2
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push5=, 16
; CHECK-NEXT: i32.add $push6=, $pop17, $pop5
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: return
%a = shl i128 %x, %y
ret i128 %a
}
define i128 @shr128(i128 %x, i128 %y) {
; CHECK-LABEL: shr128:
; CHECK: .functype shr128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push3=, __stack_pointer
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.sub $push8=, $pop3, $pop4
; CHECK-NEXT: local.tee $push7=, 5, $pop8
; CHECK-NEXT: global.set __stack_pointer, $pop7
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: i32.wrap_i64 $push0=, $pop9
; CHECK-NEXT: call __lshrti3, $pop12, $pop11, $pop10, $pop0
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push1=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop1
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push2=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop2
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push5=, 16
; CHECK-NEXT: i32.add $push6=, $pop17, $pop5
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: return
%a = lshr i128 %x, %y
ret i128 %a
}
define i128 @sar128(i128 %x, i128 %y) {
; CHECK-LABEL: sar128:
; CHECK: .functype sar128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push3=, __stack_pointer
; CHECK-NEXT: i32.const $push4=, 16
; CHECK-NEXT: i32.sub $push8=, $pop3, $pop4
; CHECK-NEXT: local.tee $push7=, 5, $pop8
; CHECK-NEXT: global.set __stack_pointer, $pop7
; CHECK-NEXT: local.get $push12=, 5
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: local.get $push9=, 3
; CHECK-NEXT: i32.wrap_i64 $push0=, $pop9
; CHECK-NEXT: call __ashrti3, $pop12, $pop11, $pop10, $pop0
; CHECK-NEXT: local.get $push14=, 0
; CHECK-NEXT: local.get $push13=, 5
; CHECK-NEXT: i64.load $push1=, 8($pop13)
; CHECK-NEXT: i64.store 8($pop14), $pop1
; CHECK-NEXT: local.get $push16=, 0
; CHECK-NEXT: local.get $push15=, 5
; CHECK-NEXT: i64.load $push2=, 0($pop15)
; CHECK-NEXT: i64.store 0($pop16), $pop2
; CHECK-NEXT: local.get $push17=, 5
; CHECK-NEXT: i32.const $push5=, 16
; CHECK-NEXT: i32.add $push6=, $pop17, $pop5
; CHECK-NEXT: global.set __stack_pointer, $pop6
; CHECK-NEXT: return
%a = ashr i128 %x, %y
ret i128 %a
}
define i128 @clz128(i128 %x) {
; CHECK-LABEL: clz128:
; CHECK: .functype clz128 (i32, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push8=, 0
; CHECK-NEXT: i64.const $push0=, 0
; CHECK-NEXT: i64.store 8($pop8), $pop0
; CHECK-NEXT: local.get $push12=, 0
; CHECK-NEXT: local.get $push9=, 2
; CHECK-NEXT: i64.clz $push5=, $pop9
; CHECK-NEXT: local.get $push10=, 1
; CHECK-NEXT: i64.clz $push2=, $pop10
; CHECK-NEXT: i64.const $push3=, 64
; CHECK-NEXT: i64.add $push4=, $pop2, $pop3
; CHECK-NEXT: local.get $push11=, 2
; CHECK-NEXT: i64.const $push7=, 0
; CHECK-NEXT: i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT: i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT: i64.store 0($pop12), $pop6
; CHECK-NEXT: return
%a = call i128 @llvm.ctlz.i128(i128 %x, i1 false)
ret i128 %a
}
define i128 @clz128_zero_undef(i128 %x) {
; CHECK-LABEL: clz128_zero_undef:
; CHECK: .functype clz128_zero_undef (i32, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push8=, 0
; CHECK-NEXT: i64.const $push0=, 0
; CHECK-NEXT: i64.store 8($pop8), $pop0
; CHECK-NEXT: local.get $push12=, 0
; CHECK-NEXT: local.get $push9=, 2
; CHECK-NEXT: i64.clz $push5=, $pop9
; CHECK-NEXT: local.get $push10=, 1
; CHECK-NEXT: i64.clz $push2=, $pop10
; CHECK-NEXT: i64.const $push3=, 64
; CHECK-NEXT: i64.add $push4=, $pop2, $pop3
; CHECK-NEXT: local.get $push11=, 2
; CHECK-NEXT: i64.const $push7=, 0
; CHECK-NEXT: i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT: i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT: i64.store 0($pop12), $pop6
; CHECK-NEXT: return
%a = call i128 @llvm.ctlz.i128(i128 %x, i1 true)
ret i128 %a
}
define i128 @ctz128(i128 %x) {
; CHECK-LABEL: ctz128:
; CHECK: .functype ctz128 (i32, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push8=, 0
; CHECK-NEXT: i64.const $push0=, 0
; CHECK-NEXT: i64.store 8($pop8), $pop0
; CHECK-NEXT: local.get $push12=, 0
; CHECK-NEXT: local.get $push9=, 1
; CHECK-NEXT: i64.ctz $push5=, $pop9
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: i64.ctz $push2=, $pop10
; CHECK-NEXT: i64.const $push3=, 64
; CHECK-NEXT: i64.add $push4=, $pop2, $pop3
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: i64.const $push7=, 0
; CHECK-NEXT: i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT: i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT: i64.store 0($pop12), $pop6
; CHECK-NEXT: return
%a = call i128 @llvm.cttz.i128(i128 %x, i1 false)
ret i128 %a
}
define i128 @ctz128_zero_undef(i128 %x) {
; CHECK-LABEL: ctz128_zero_undef:
; CHECK: .functype ctz128_zero_undef (i32, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push8=, 0
; CHECK-NEXT: i64.const $push0=, 0
; CHECK-NEXT: i64.store 8($pop8), $pop0
; CHECK-NEXT: local.get $push12=, 0
; CHECK-NEXT: local.get $push9=, 1
; CHECK-NEXT: i64.ctz $push5=, $pop9
; CHECK-NEXT: local.get $push10=, 2
; CHECK-NEXT: i64.ctz $push2=, $pop10
; CHECK-NEXT: i64.const $push3=, 64
; CHECK-NEXT: i64.add $push4=, $pop2, $pop3
; CHECK-NEXT: local.get $push11=, 1
; CHECK-NEXT: i64.const $push7=, 0
; CHECK-NEXT: i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT: i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT: i64.store 0($pop12), $pop6
; CHECK-NEXT: return
%a = call i128 @llvm.cttz.i128(i128 %x, i1 true)
ret i128 %a
}
define i128 @popcnt128(i128 %x) {
; CHECK-LABEL: popcnt128:
; CHECK: .functype popcnt128 (i32, i64, i64) -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push4=, 0
; CHECK-NEXT: i64.const $push0=, 0
; CHECK-NEXT: i64.store 8($pop4), $pop0
; CHECK-NEXT: local.get $push7=, 0
; CHECK-NEXT: local.get $push5=, 1
; CHECK-NEXT: i64.popcnt $push2=, $pop5
; CHECK-NEXT: local.get $push6=, 2
; CHECK-NEXT: i64.popcnt $push1=, $pop6
; CHECK-NEXT: i64.add $push3=, $pop2, $pop1
; CHECK-NEXT: i64.store 0($pop7), $pop3
; CHECK-NEXT: return
%a = call i128 @llvm.ctpop.i128(i128 %x)
ret i128 %a
}
define i32 @eqz128(i128 %x) {
; CHECK-LABEL: eqz128:
; CHECK: .functype eqz128 (i64, i64) -> (i32)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get $push3=, 0
; CHECK-NEXT: local.get $push2=, 1
; CHECK-NEXT: i64.or $push0=, $pop3, $pop2
; CHECK-NEXT: i64.eqz $push1=, $pop0
; CHECK-NEXT: return $pop1
%a = icmp eq i128 %x, 0
%b = zext i1 %a to i32
ret i32 %b
}
define i128 @rotl(i128 %x, i128 %y) {
; CHECK-LABEL: rotl:
; CHECK: .functype rotl (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push8=, __stack_pointer
; CHECK-NEXT: i32.const $push9=, 32
; CHECK-NEXT: i32.sub $push17=, $pop8, $pop9
; CHECK-NEXT: local.tee $push16=, 5, $pop17
; CHECK-NEXT: global.set __stack_pointer, $pop16
; CHECK-NEXT: local.get $push18=, 5
; CHECK-NEXT: i32.const $push12=, 16
; CHECK-NEXT: i32.add $push13=, $pop18, $pop12
; CHECK-NEXT: local.get $push21=, 1
; CHECK-NEXT: local.get $push20=, 2
; CHECK-NEXT: local.get $push19=, 3
; CHECK-NEXT: i32.wrap_i64 $push15=, $pop19
; CHECK-NEXT: local.tee $push14=, 6, $pop15
; CHECK-NEXT: call __ashlti3, $pop13, $pop21, $pop20, $pop14
; CHECK-NEXT: local.get $push25=, 5
; CHECK-NEXT: local.get $push24=, 1
; CHECK-NEXT: local.get $push23=, 2
; CHECK-NEXT: i32.const $push0=, 128
; CHECK-NEXT: local.get $push22=, 6
; CHECK-NEXT: i32.sub $push1=, $pop0, $pop22
; CHECK-NEXT: call __lshrti3, $pop25, $pop24, $pop23, $pop1
; CHECK-NEXT: local.get $push28=, 0
; CHECK-NEXT: local.get $push26=, 5
; CHECK-NEXT: i64.load $push2=, 24($pop26)
; CHECK-NEXT: local.get $push27=, 5
; CHECK-NEXT: i64.load $push3=, 8($pop27)
; CHECK-NEXT: i64.or $push4=, $pop2, $pop3
; CHECK-NEXT: i64.store 8($pop28), $pop4
; CHECK-NEXT: local.get $push31=, 0
; CHECK-NEXT: local.get $push29=, 5
; CHECK-NEXT: i64.load $push5=, 16($pop29)
; CHECK-NEXT: local.get $push30=, 5
; CHECK-NEXT: i64.load $push6=, 0($pop30)
; CHECK-NEXT: i64.or $push7=, $pop5, $pop6
; CHECK-NEXT: i64.store 0($pop31), $pop7
; CHECK-NEXT: local.get $push32=, 5
; CHECK-NEXT: i32.const $push10=, 32
; CHECK-NEXT: i32.add $push11=, $pop32, $pop10
; CHECK-NEXT: global.set __stack_pointer, $pop11
; CHECK-NEXT: return
%z = sub i128 128, %y
%b = shl i128 %x, %y
%c = lshr i128 %x, %z
%d = or i128 %b, %c
ret i128 %d
}
define i128 @masked_rotl(i128 %x, i128 %y) {
; CHECK-LABEL: masked_rotl:
; CHECK: .functype masked_rotl (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push10=, __stack_pointer
; CHECK-NEXT: i32.const $push11=, 32
; CHECK-NEXT: i32.sub $push19=, $pop10, $pop11
; CHECK-NEXT: local.tee $push18=, 5, $pop19
; CHECK-NEXT: global.set __stack_pointer, $pop18
; CHECK-NEXT: local.get $push20=, 5
; CHECK-NEXT: i32.const $push14=, 16
; CHECK-NEXT: i32.add $push15=, $pop20, $pop14
; CHECK-NEXT: local.get $push23=, 1
; CHECK-NEXT: local.get $push22=, 2
; CHECK-NEXT: local.get $push21=, 3
; CHECK-NEXT: i32.wrap_i64 $push0=, $pop21
; CHECK-NEXT: i32.const $push1=, 127
; CHECK-NEXT: i32.and $push17=, $pop0, $pop1
; CHECK-NEXT: local.tee $push16=, 6, $pop17
; CHECK-NEXT: call __ashlti3, $pop15, $pop23, $pop22, $pop16
; CHECK-NEXT: local.get $push27=, 5
; CHECK-NEXT: local.get $push26=, 1
; CHECK-NEXT: local.get $push25=, 2
; CHECK-NEXT: i32.const $push2=, 128
; CHECK-NEXT: local.get $push24=, 6
; CHECK-NEXT: i32.sub $push3=, $pop2, $pop24
; CHECK-NEXT: call __lshrti3, $pop27, $pop26, $pop25, $pop3
; CHECK-NEXT: local.get $push30=, 0
; CHECK-NEXT: local.get $push28=, 5
; CHECK-NEXT: i64.load $push4=, 24($pop28)
; CHECK-NEXT: local.get $push29=, 5
; CHECK-NEXT: i64.load $push5=, 8($pop29)
; CHECK-NEXT: i64.or $push6=, $pop4, $pop5
; CHECK-NEXT: i64.store 8($pop30), $pop6
; CHECK-NEXT: local.get $push33=, 0
; CHECK-NEXT: local.get $push31=, 5
; CHECK-NEXT: i64.load $push7=, 16($pop31)
; CHECK-NEXT: local.get $push32=, 5
; CHECK-NEXT: i64.load $push8=, 0($pop32)
; CHECK-NEXT: i64.or $push9=, $pop7, $pop8
; CHECK-NEXT: i64.store 0($pop33), $pop9
; CHECK-NEXT: local.get $push34=, 5
; CHECK-NEXT: i32.const $push12=, 32
; CHECK-NEXT: i32.add $push13=, $pop34, $pop12
; CHECK-NEXT: global.set __stack_pointer, $pop13
; CHECK-NEXT: return
%a = and i128 %y, 127
%z = sub i128 128, %a
%b = shl i128 %x, %a
%c = lshr i128 %x, %z
%d = or i128 %b, %c
ret i128 %d
}
define i128 @rotr(i128 %x, i128 %y) {
; CHECK-LABEL: rotr:
; CHECK: .functype rotr (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push8=, __stack_pointer
; CHECK-NEXT: i32.const $push9=, 32
; CHECK-NEXT: i32.sub $push17=, $pop8, $pop9
; CHECK-NEXT: local.tee $push16=, 5, $pop17
; CHECK-NEXT: global.set __stack_pointer, $pop16
; CHECK-NEXT: local.get $push18=, 5
; CHECK-NEXT: i32.const $push12=, 16
; CHECK-NEXT: i32.add $push13=, $pop18, $pop12
; CHECK-NEXT: local.get $push21=, 1
; CHECK-NEXT: local.get $push20=, 2
; CHECK-NEXT: local.get $push19=, 3
; CHECK-NEXT: i32.wrap_i64 $push15=, $pop19
; CHECK-NEXT: local.tee $push14=, 6, $pop15
; CHECK-NEXT: call __lshrti3, $pop13, $pop21, $pop20, $pop14
; CHECK-NEXT: local.get $push25=, 5
; CHECK-NEXT: local.get $push24=, 1
; CHECK-NEXT: local.get $push23=, 2
; CHECK-NEXT: i32.const $push0=, 128
; CHECK-NEXT: local.get $push22=, 6
; CHECK-NEXT: i32.sub $push1=, $pop0, $pop22
; CHECK-NEXT: call __ashlti3, $pop25, $pop24, $pop23, $pop1
; CHECK-NEXT: local.get $push28=, 0
; CHECK-NEXT: local.get $push26=, 5
; CHECK-NEXT: i64.load $push2=, 24($pop26)
; CHECK-NEXT: local.get $push27=, 5
; CHECK-NEXT: i64.load $push3=, 8($pop27)
; CHECK-NEXT: i64.or $push4=, $pop2, $pop3
; CHECK-NEXT: i64.store 8($pop28), $pop4
; CHECK-NEXT: local.get $push31=, 0
; CHECK-NEXT: local.get $push29=, 5
; CHECK-NEXT: i64.load $push5=, 16($pop29)
; CHECK-NEXT: local.get $push30=, 5
; CHECK-NEXT: i64.load $push6=, 0($pop30)
; CHECK-NEXT: i64.or $push7=, $pop5, $pop6
; CHECK-NEXT: i64.store 0($pop31), $pop7
; CHECK-NEXT: local.get $push32=, 5
; CHECK-NEXT: i32.const $push10=, 32
; CHECK-NEXT: i32.add $push11=, $pop32, $pop10
; CHECK-NEXT: global.set __stack_pointer, $pop11
; CHECK-NEXT: return
%z = sub i128 128, %y
%b = lshr i128 %x, %y
%c = shl i128 %x, %z
%d = or i128 %b, %c
ret i128 %d
}
define i128 @masked_rotr(i128 %x, i128 %y) {
; CHECK-LABEL: masked_rotr:
; CHECK: .functype masked_rotr (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: global.get $push10=, __stack_pointer
; CHECK-NEXT: i32.const $push11=, 32
; CHECK-NEXT: i32.sub $push19=, $pop10, $pop11
; CHECK-NEXT: local.tee $push18=, 5, $pop19
; CHECK-NEXT: global.set __stack_pointer, $pop18
; CHECK-NEXT: local.get $push20=, 5
; CHECK-NEXT: i32.const $push14=, 16
; CHECK-NEXT: i32.add $push15=, $pop20, $pop14
; CHECK-NEXT: local.get $push23=, 1
; CHECK-NEXT: local.get $push22=, 2
; CHECK-NEXT: local.get $push21=, 3
; CHECK-NEXT: i32.wrap_i64 $push0=, $pop21
; CHECK-NEXT: i32.const $push1=, 127
; CHECK-NEXT: i32.and $push17=, $pop0, $pop1
; CHECK-NEXT: local.tee $push16=, 6, $pop17
; CHECK-NEXT: call __lshrti3, $pop15, $pop23, $pop22, $pop16
; CHECK-NEXT: local.get $push27=, 5
; CHECK-NEXT: local.get $push26=, 1
; CHECK-NEXT: local.get $push25=, 2
; CHECK-NEXT: i32.const $push2=, 128
; CHECK-NEXT: local.get $push24=, 6
; CHECK-NEXT: i32.sub $push3=, $pop2, $pop24
; CHECK-NEXT: call __ashlti3, $pop27, $pop26, $pop25, $pop3
; CHECK-NEXT: local.get $push30=, 0
; CHECK-NEXT: local.get $push28=, 5
; CHECK-NEXT: i64.load $push4=, 24($pop28)
; CHECK-NEXT: local.get $push29=, 5
; CHECK-NEXT: i64.load $push5=, 8($pop29)
; CHECK-NEXT: i64.or $push6=, $pop4, $pop5
; CHECK-NEXT: i64.store 8($pop30), $pop6
; CHECK-NEXT: local.get $push33=, 0
; CHECK-NEXT: local.get $push31=, 5
; CHECK-NEXT: i64.load $push7=, 16($pop31)
; CHECK-NEXT: local.get $push32=, 5
; CHECK-NEXT: i64.load $push8=, 0($pop32)
; CHECK-NEXT: i64.or $push9=, $pop7, $pop8
; CHECK-NEXT: i64.store 0($pop33), $pop9
; CHECK-NEXT: local.get $push34=, 5
; CHECK-NEXT: i32.const $push12=, 32
; CHECK-NEXT: i32.add $push13=, $pop34, $pop12
; CHECK-NEXT: global.set __stack_pointer, $pop13
; CHECK-NEXT: return
%a = and i128 %y, 127
%z = sub i128 128, %a
%b = lshr i128 %x, %a
%c = shl i128 %x, %z
%d = or i128 %b, %c
ret i128 %d
}