| ; 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 $push4=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push5=, 16 |
| ; CHECK-NEXT: i32.sub $push9=, $pop4, $pop5 |
| ; CHECK-NEXT: local.tee $push8=, 5, $pop9 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: local.get $push10=, 4 |
| ; CHECK-NEXT: call __multi3, $pop14, $pop13, $pop12, $pop11, $pop10 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push0=, 8 |
| ; CHECK-NEXT: i32.add $push1=, $pop15, $pop0 |
| ; CHECK-NEXT: i64.load $push2=, 0($pop1) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop2 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop3 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.add $push7=, $pop19, $pop6 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop7 |
| ; 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 $push4=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push5=, 16 |
| ; CHECK-NEXT: i32.sub $push9=, $pop4, $pop5 |
| ; CHECK-NEXT: local.tee $push8=, 5, $pop9 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: local.get $push10=, 4 |
| ; CHECK-NEXT: call __divti3, $pop14, $pop13, $pop12, $pop11, $pop10 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push0=, 8 |
| ; CHECK-NEXT: i32.add $push1=, $pop15, $pop0 |
| ; CHECK-NEXT: i64.load $push2=, 0($pop1) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop2 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop3 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.add $push7=, $pop19, $pop6 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop7 |
| ; 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 $push4=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push5=, 16 |
| ; CHECK-NEXT: i32.sub $push9=, $pop4, $pop5 |
| ; CHECK-NEXT: local.tee $push8=, 5, $pop9 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: local.get $push10=, 4 |
| ; CHECK-NEXT: call __udivti3, $pop14, $pop13, $pop12, $pop11, $pop10 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push0=, 8 |
| ; CHECK-NEXT: i32.add $push1=, $pop15, $pop0 |
| ; CHECK-NEXT: i64.load $push2=, 0($pop1) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop2 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop3 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.add $push7=, $pop19, $pop6 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop7 |
| ; 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 $push4=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push5=, 16 |
| ; CHECK-NEXT: i32.sub $push9=, $pop4, $pop5 |
| ; CHECK-NEXT: local.tee $push8=, 5, $pop9 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: local.get $push10=, 4 |
| ; CHECK-NEXT: call __modti3, $pop14, $pop13, $pop12, $pop11, $pop10 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push0=, 8 |
| ; CHECK-NEXT: i32.add $push1=, $pop15, $pop0 |
| ; CHECK-NEXT: i64.load $push2=, 0($pop1) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop2 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop3 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.add $push7=, $pop19, $pop6 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop7 |
| ; 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 $push4=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push5=, 16 |
| ; CHECK-NEXT: i32.sub $push9=, $pop4, $pop5 |
| ; CHECK-NEXT: local.tee $push8=, 5, $pop9 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: local.get $push10=, 4 |
| ; CHECK-NEXT: call __umodti3, $pop14, $pop13, $pop12, $pop11, $pop10 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push0=, 8 |
| ; CHECK-NEXT: i32.add $push1=, $pop15, $pop0 |
| ; CHECK-NEXT: i64.load $push2=, 0($pop1) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop2 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop3 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.add $push7=, $pop19, $pop6 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop7 |
| ; 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 $push5=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.sub $push10=, $pop5, $pop6 |
| ; CHECK-NEXT: local.tee $push9=, 5, $pop10 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop9 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: i32.wrap_i64 $push0=, $pop11 |
| ; CHECK-NEXT: call __ashlti3, $pop14, $pop13, $pop12, $pop0 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push1=, 8 |
| ; CHECK-NEXT: i32.add $push2=, $pop15, $pop1 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop2) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop3 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push4=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop4 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push7=, 16 |
| ; CHECK-NEXT: i32.add $push8=, $pop19, $pop7 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; 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 $push5=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.sub $push10=, $pop5, $pop6 |
| ; CHECK-NEXT: local.tee $push9=, 5, $pop10 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop9 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: i32.wrap_i64 $push0=, $pop11 |
| ; CHECK-NEXT: call __lshrti3, $pop14, $pop13, $pop12, $pop0 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push1=, 8 |
| ; CHECK-NEXT: i32.add $push2=, $pop15, $pop1 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop2) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop3 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push4=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop4 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push7=, 16 |
| ; CHECK-NEXT: i32.add $push8=, $pop19, $pop7 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; 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 $push5=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push6=, 16 |
| ; CHECK-NEXT: i32.sub $push10=, $pop5, $pop6 |
| ; CHECK-NEXT: local.tee $push9=, 5, $pop10 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop9 |
| ; CHECK-NEXT: local.get $push14=, 5 |
| ; CHECK-NEXT: local.get $push13=, 1 |
| ; CHECK-NEXT: local.get $push12=, 2 |
| ; CHECK-NEXT: local.get $push11=, 3 |
| ; CHECK-NEXT: i32.wrap_i64 $push0=, $pop11 |
| ; CHECK-NEXT: call __ashrti3, $pop14, $pop13, $pop12, $pop0 |
| ; CHECK-NEXT: local.get $push16=, 0 |
| ; CHECK-NEXT: local.get $push15=, 5 |
| ; CHECK-NEXT: i32.const $push1=, 8 |
| ; CHECK-NEXT: i32.add $push2=, $pop15, $pop1 |
| ; CHECK-NEXT: i64.load $push3=, 0($pop2) |
| ; CHECK-NEXT: i64.store 8($pop16), $pop3 |
| ; CHECK-NEXT: local.get $push18=, 0 |
| ; CHECK-NEXT: local.get $push17=, 5 |
| ; CHECK-NEXT: i64.load $push4=, 0($pop17) |
| ; CHECK-NEXT: i64.store 0($pop18), $pop4 |
| ; CHECK-NEXT: local.get $push19=, 5 |
| ; CHECK-NEXT: i32.const $push7=, 16 |
| ; CHECK-NEXT: i32.add $push8=, $pop19, $pop7 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop8 |
| ; 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 $push11=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push12=, 32 |
| ; CHECK-NEXT: i32.sub $push23=, $pop11, $pop12 |
| ; CHECK-NEXT: local.tee $push22=, 5, $pop23 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop22 |
| ; CHECK-NEXT: local.get $push24=, 5 |
| ; CHECK-NEXT: i32.const $push17=, 16 |
| ; CHECK-NEXT: i32.add $push18=, $pop24, $pop17 |
| ; CHECK-NEXT: local.get $push27=, 1 |
| ; CHECK-NEXT: local.get $push26=, 2 |
| ; CHECK-NEXT: local.get $push25=, 3 |
| ; CHECK-NEXT: i32.wrap_i64 $push21=, $pop25 |
| ; CHECK-NEXT: local.tee $push20=, 6, $pop21 |
| ; CHECK-NEXT: call __ashlti3, $pop18, $pop27, $pop26, $pop20 |
| ; CHECK-NEXT: local.get $push31=, 5 |
| ; CHECK-NEXT: local.get $push30=, 1 |
| ; CHECK-NEXT: local.get $push29=, 2 |
| ; CHECK-NEXT: i32.const $push0=, 128 |
| ; CHECK-NEXT: local.get $push28=, 6 |
| ; CHECK-NEXT: i32.sub $push1=, $pop0, $pop28 |
| ; CHECK-NEXT: call __lshrti3, $pop31, $pop30, $pop29, $pop1 |
| ; CHECK-NEXT: local.get $push34=, 0 |
| ; CHECK-NEXT: local.get $push32=, 5 |
| ; CHECK-NEXT: i32.const $push15=, 16 |
| ; CHECK-NEXT: i32.add $push16=, $pop32, $pop15 |
| ; CHECK-NEXT: i32.const $push2=, 8 |
| ; CHECK-NEXT: i32.add $push3=, $pop16, $pop2 |
| ; CHECK-NEXT: i64.load $push4=, 0($pop3) |
| ; CHECK-NEXT: local.get $push33=, 5 |
| ; CHECK-NEXT: i32.const $push19=, 8 |
| ; CHECK-NEXT: i32.add $push5=, $pop33, $pop19 |
| ; CHECK-NEXT: i64.load $push6=, 0($pop5) |
| ; CHECK-NEXT: i64.or $push7=, $pop4, $pop6 |
| ; CHECK-NEXT: i64.store 8($pop34), $pop7 |
| ; CHECK-NEXT: local.get $push37=, 0 |
| ; CHECK-NEXT: local.get $push35=, 5 |
| ; CHECK-NEXT: i64.load $push8=, 16($pop35) |
| ; CHECK-NEXT: local.get $push36=, 5 |
| ; CHECK-NEXT: i64.load $push9=, 0($pop36) |
| ; CHECK-NEXT: i64.or $push10=, $pop8, $pop9 |
| ; CHECK-NEXT: i64.store 0($pop37), $pop10 |
| ; CHECK-NEXT: local.get $push38=, 5 |
| ; CHECK-NEXT: i32.const $push13=, 32 |
| ; CHECK-NEXT: i32.add $push14=, $pop38, $pop13 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop14 |
| ; 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 $push13=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push14=, 32 |
| ; CHECK-NEXT: i32.sub $push25=, $pop13, $pop14 |
| ; CHECK-NEXT: local.tee $push24=, 5, $pop25 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop24 |
| ; CHECK-NEXT: local.get $push26=, 5 |
| ; CHECK-NEXT: i32.const $push19=, 16 |
| ; CHECK-NEXT: i32.add $push20=, $pop26, $pop19 |
| ; CHECK-NEXT: local.get $push29=, 1 |
| ; CHECK-NEXT: local.get $push28=, 2 |
| ; CHECK-NEXT: local.get $push27=, 3 |
| ; CHECK-NEXT: i32.wrap_i64 $push0=, $pop27 |
| ; CHECK-NEXT: i32.const $push1=, 127 |
| ; CHECK-NEXT: i32.and $push23=, $pop0, $pop1 |
| ; CHECK-NEXT: local.tee $push22=, 6, $pop23 |
| ; CHECK-NEXT: call __ashlti3, $pop20, $pop29, $pop28, $pop22 |
| ; CHECK-NEXT: local.get $push33=, 5 |
| ; CHECK-NEXT: local.get $push32=, 1 |
| ; CHECK-NEXT: local.get $push31=, 2 |
| ; CHECK-NEXT: i32.const $push2=, 128 |
| ; CHECK-NEXT: local.get $push30=, 6 |
| ; CHECK-NEXT: i32.sub $push3=, $pop2, $pop30 |
| ; CHECK-NEXT: call __lshrti3, $pop33, $pop32, $pop31, $pop3 |
| ; CHECK-NEXT: local.get $push36=, 0 |
| ; CHECK-NEXT: local.get $push34=, 5 |
| ; CHECK-NEXT: i32.const $push17=, 16 |
| ; CHECK-NEXT: i32.add $push18=, $pop34, $pop17 |
| ; CHECK-NEXT: i32.const $push4=, 8 |
| ; CHECK-NEXT: i32.add $push5=, $pop18, $pop4 |
| ; CHECK-NEXT: i64.load $push6=, 0($pop5) |
| ; CHECK-NEXT: local.get $push35=, 5 |
| ; CHECK-NEXT: i32.const $push21=, 8 |
| ; CHECK-NEXT: i32.add $push7=, $pop35, $pop21 |
| ; CHECK-NEXT: i64.load $push8=, 0($pop7) |
| ; CHECK-NEXT: i64.or $push9=, $pop6, $pop8 |
| ; CHECK-NEXT: i64.store 8($pop36), $pop9 |
| ; CHECK-NEXT: local.get $push39=, 0 |
| ; CHECK-NEXT: local.get $push37=, 5 |
| ; CHECK-NEXT: i64.load $push10=, 16($pop37) |
| ; CHECK-NEXT: local.get $push38=, 5 |
| ; CHECK-NEXT: i64.load $push11=, 0($pop38) |
| ; CHECK-NEXT: i64.or $push12=, $pop10, $pop11 |
| ; CHECK-NEXT: i64.store 0($pop39), $pop12 |
| ; CHECK-NEXT: local.get $push40=, 5 |
| ; CHECK-NEXT: i32.const $push15=, 32 |
| ; CHECK-NEXT: i32.add $push16=, $pop40, $pop15 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop16 |
| ; 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 $push11=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push12=, 32 |
| ; CHECK-NEXT: i32.sub $push23=, $pop11, $pop12 |
| ; CHECK-NEXT: local.tee $push22=, 5, $pop23 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop22 |
| ; CHECK-NEXT: local.get $push24=, 5 |
| ; CHECK-NEXT: i32.const $push17=, 16 |
| ; CHECK-NEXT: i32.add $push18=, $pop24, $pop17 |
| ; CHECK-NEXT: local.get $push27=, 1 |
| ; CHECK-NEXT: local.get $push26=, 2 |
| ; CHECK-NEXT: local.get $push25=, 3 |
| ; CHECK-NEXT: i32.wrap_i64 $push21=, $pop25 |
| ; CHECK-NEXT: local.tee $push20=, 6, $pop21 |
| ; CHECK-NEXT: call __lshrti3, $pop18, $pop27, $pop26, $pop20 |
| ; CHECK-NEXT: local.get $push31=, 5 |
| ; CHECK-NEXT: local.get $push30=, 1 |
| ; CHECK-NEXT: local.get $push29=, 2 |
| ; CHECK-NEXT: i32.const $push0=, 128 |
| ; CHECK-NEXT: local.get $push28=, 6 |
| ; CHECK-NEXT: i32.sub $push1=, $pop0, $pop28 |
| ; CHECK-NEXT: call __ashlti3, $pop31, $pop30, $pop29, $pop1 |
| ; CHECK-NEXT: local.get $push34=, 0 |
| ; CHECK-NEXT: local.get $push32=, 5 |
| ; CHECK-NEXT: i32.const $push15=, 16 |
| ; CHECK-NEXT: i32.add $push16=, $pop32, $pop15 |
| ; CHECK-NEXT: i32.const $push2=, 8 |
| ; CHECK-NEXT: i32.add $push3=, $pop16, $pop2 |
| ; CHECK-NEXT: i64.load $push4=, 0($pop3) |
| ; CHECK-NEXT: local.get $push33=, 5 |
| ; CHECK-NEXT: i32.const $push19=, 8 |
| ; CHECK-NEXT: i32.add $push5=, $pop33, $pop19 |
| ; CHECK-NEXT: i64.load $push6=, 0($pop5) |
| ; CHECK-NEXT: i64.or $push7=, $pop4, $pop6 |
| ; CHECK-NEXT: i64.store 8($pop34), $pop7 |
| ; CHECK-NEXT: local.get $push37=, 0 |
| ; CHECK-NEXT: local.get $push35=, 5 |
| ; CHECK-NEXT: i64.load $push8=, 16($pop35) |
| ; CHECK-NEXT: local.get $push36=, 5 |
| ; CHECK-NEXT: i64.load $push9=, 0($pop36) |
| ; CHECK-NEXT: i64.or $push10=, $pop8, $pop9 |
| ; CHECK-NEXT: i64.store 0($pop37), $pop10 |
| ; CHECK-NEXT: local.get $push38=, 5 |
| ; CHECK-NEXT: i32.const $push13=, 32 |
| ; CHECK-NEXT: i32.add $push14=, $pop38, $pop13 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop14 |
| ; 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 $push13=, __stack_pointer |
| ; CHECK-NEXT: i32.const $push14=, 32 |
| ; CHECK-NEXT: i32.sub $push25=, $pop13, $pop14 |
| ; CHECK-NEXT: local.tee $push24=, 5, $pop25 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop24 |
| ; CHECK-NEXT: local.get $push26=, 5 |
| ; CHECK-NEXT: i32.const $push19=, 16 |
| ; CHECK-NEXT: i32.add $push20=, $pop26, $pop19 |
| ; CHECK-NEXT: local.get $push29=, 1 |
| ; CHECK-NEXT: local.get $push28=, 2 |
| ; CHECK-NEXT: local.get $push27=, 3 |
| ; CHECK-NEXT: i32.wrap_i64 $push0=, $pop27 |
| ; CHECK-NEXT: i32.const $push1=, 127 |
| ; CHECK-NEXT: i32.and $push23=, $pop0, $pop1 |
| ; CHECK-NEXT: local.tee $push22=, 6, $pop23 |
| ; CHECK-NEXT: call __lshrti3, $pop20, $pop29, $pop28, $pop22 |
| ; CHECK-NEXT: local.get $push33=, 5 |
| ; CHECK-NEXT: local.get $push32=, 1 |
| ; CHECK-NEXT: local.get $push31=, 2 |
| ; CHECK-NEXT: i32.const $push2=, 128 |
| ; CHECK-NEXT: local.get $push30=, 6 |
| ; CHECK-NEXT: i32.sub $push3=, $pop2, $pop30 |
| ; CHECK-NEXT: call __ashlti3, $pop33, $pop32, $pop31, $pop3 |
| ; CHECK-NEXT: local.get $push36=, 0 |
| ; CHECK-NEXT: local.get $push34=, 5 |
| ; CHECK-NEXT: i32.const $push17=, 16 |
| ; CHECK-NEXT: i32.add $push18=, $pop34, $pop17 |
| ; CHECK-NEXT: i32.const $push4=, 8 |
| ; CHECK-NEXT: i32.add $push5=, $pop18, $pop4 |
| ; CHECK-NEXT: i64.load $push6=, 0($pop5) |
| ; CHECK-NEXT: local.get $push35=, 5 |
| ; CHECK-NEXT: i32.const $push21=, 8 |
| ; CHECK-NEXT: i32.add $push7=, $pop35, $pop21 |
| ; CHECK-NEXT: i64.load $push8=, 0($pop7) |
| ; CHECK-NEXT: i64.or $push9=, $pop6, $pop8 |
| ; CHECK-NEXT: i64.store 8($pop36), $pop9 |
| ; CHECK-NEXT: local.get $push39=, 0 |
| ; CHECK-NEXT: local.get $push37=, 5 |
| ; CHECK-NEXT: i64.load $push10=, 16($pop37) |
| ; CHECK-NEXT: local.get $push38=, 5 |
| ; CHECK-NEXT: i64.load $push11=, 0($pop38) |
| ; CHECK-NEXT: i64.or $push12=, $pop10, $pop11 |
| ; CHECK-NEXT: i64.store 0($pop39), $pop12 |
| ; CHECK-NEXT: local.get $push40=, 5 |
| ; CHECK-NEXT: i32.const $push15=, 32 |
| ; CHECK-NEXT: i32.add $push16=, $pop40, $pop15 |
| ; CHECK-NEXT: global.set __stack_pointer, $pop16 |
| ; 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 |
| } |