1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s 2 3; Test that basic 128-bit integer operations assemble as expected. 4 5target triple = "wasm32-unknown-unknown" 6 7declare i128 @llvm.ctlz.i128(i128, i1) 8declare i128 @llvm.cttz.i128(i128, i1) 9declare i128 @llvm.ctpop.i128(i128) 10 11; CHECK-LABEL: add128: 12; CHECK-NEXT: .functype add128 (i32, i64, i64, i64, i64) -> (){{$}} 13; CHECK-NOT: .result 14; CHECK: i64.add 15; CHECK: i64.store 16; CHECK: i64.add 17; CHECK: i64.store 18; CHECK-NEXT: return{{$}} 19define i128 @add128(i128 %x, i128 %y) { 20 %a = add i128 %x, %y 21 ret i128 %a 22} 23 24; CHECK-LABEL: sub128: 25; CHECK-NEXT: .functype sub128 (i32, i64, i64, i64, i64) -> (){{$}} 26; CHECK: i64.sub 27; CHECK: i64.store 28; CHECK: i64.sub 29; CHECK: i64.store 30; CHECK-NEXT: return{{$}} 31define i128 @sub128(i128 %x, i128 %y) { 32 %a = sub i128 %x, %y 33 ret i128 %a 34} 35 36; CHECK-LABEL: mul128: 37; CHECK-NEXT: .functype mul128 (i32, i64, i64, i64, i64) -> (){{$}} 38; CHECK: call __multi3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 39; CHECK: return{{$}} 40define i128 @mul128(i128 %x, i128 %y) { 41 %a = mul i128 %x, %y 42 ret i128 %a 43} 44 45; CHECK-LABEL: sdiv128: 46; CHECK-NEXT: .functype sdiv128 (i32, i64, i64, i64, i64) -> (){{$}} 47; CHECK: call __divti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 48; CHECK: return{{$}} 49define i128 @sdiv128(i128 %x, i128 %y) { 50 %a = sdiv i128 %x, %y 51 ret i128 %a 52} 53 54; CHECK-LABEL: udiv128: 55; CHECK-NEXT: .functype udiv128 (i32, i64, i64, i64, i64) -> (){{$}} 56; CHECK: call __udivti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 57; CHECK: return{{$}} 58define i128 @udiv128(i128 %x, i128 %y) { 59 %a = udiv i128 %x, %y 60 ret i128 %a 61} 62 63; CHECK-LABEL: srem128: 64; CHECK-NEXT: .functype srem128 (i32, i64, i64, i64, i64) -> (){{$}} 65; CHECK: call __modti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 66; CHECK: return{{$}} 67define i128 @srem128(i128 %x, i128 %y) { 68 %a = srem i128 %x, %y 69 ret i128 %a 70} 71 72; CHECK-LABEL: urem128: 73; CHECK-NEXT: .functype urem128 (i32, i64, i64, i64, i64) -> (){{$}} 74; CHECK: call __umodti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 75; CHECK: return{{$}} 76define i128 @urem128(i128 %x, i128 %y) { 77 %a = urem i128 %x, %y 78 ret i128 %a 79} 80 81; CHECK-LABEL: and128: 82; CHECK-NEXT: .functype and128 (i32, i64, i64, i64, i64) -> (){{$}} 83; CHECK-NOT: .result 84; CHECK: i64.and 85; CHECK: i64.store 86; CHECK: i64.and 87; CHECK: i64.store 88; CHECK-NEXT: return{{$}} 89define i128 @and128(i128 %x, i128 %y) { 90 %a = and i128 %x, %y 91 ret i128 %a 92} 93 94; CHECK-LABEL: or128: 95; CHECK-NEXT: .functype or128 (i32, i64, i64, i64, i64) -> (){{$}} 96; CHECK: i64.or 97; CHECK: i64.store 98; CHECK: i64.or 99; CHECK: i64.store 100; CHECK-NEXT: return{{$}} 101define i128 @or128(i128 %x, i128 %y) { 102 %a = or i128 %x, %y 103 ret i128 %a 104} 105 106; CHECK-LABEL: xor128: 107; CHECK-NEXT: .functype xor128 (i32, i64, i64, i64, i64) -> (){{$}} 108; CHECK: i64.xor 109; CHECK: i64.store 110; CHECK: i64.xor 111; CHECK: i64.store 112; CHECK-NEXT: return{{$}} 113define i128 @xor128(i128 %x, i128 %y) { 114 %a = xor i128 %x, %y 115 ret i128 %a 116} 117 118; CHECK-LABEL: shl128: 119; CHECK-NEXT: .functype shl128 (i32, i64, i64, i64, i64) -> (){{$}} 120; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 121; CHECK: return{{$}} 122define i128 @shl128(i128 %x, i128 %y) { 123 %a = shl i128 %x, %y 124 ret i128 %a 125} 126 127; CHECK-LABEL: shr128: 128; CHECK-NEXT: .functype shr128 (i32, i64, i64, i64, i64) -> (){{$}} 129; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 130; CHECK: return{{$}} 131define i128 @shr128(i128 %x, i128 %y) { 132 %a = lshr i128 %x, %y 133 ret i128 %a 134} 135 136; CHECK-LABEL: sar128: 137; CHECK-NEXT: .functype sar128 (i32, i64, i64, i64, i64) -> (){{$}} 138; CHECK: call __ashrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 139; CHECK: return{{$}} 140define i128 @sar128(i128 %x, i128 %y) { 141 %a = ashr i128 %x, %y 142 ret i128 %a 143} 144 145; CHECK-LABEL: clz128: 146; CHECK-NEXT: .functype clz128 (i32, i64, i64) -> (){{$}} 147; CHECK-NOT: .result 148; CHECK: i64.clz 149; CHECK: i64.clz 150; CHECK: return{{$}} 151define i128 @clz128(i128 %x) { 152 %a = call i128 @llvm.ctlz.i128(i128 %x, i1 false) 153 ret i128 %a 154} 155 156; CHECK-LABEL: clz128_zero_undef: 157; CHECK-NEXT: .functype clz128_zero_undef (i32, i64, i64) -> (){{$}} 158; CHECK: i64.clz 159; CHECK: i64.clz 160; CHECK: return{{$}} 161define i128 @clz128_zero_undef(i128 %x) { 162 %a = call i128 @llvm.ctlz.i128(i128 %x, i1 true) 163 ret i128 %a 164} 165 166; CHECK-LABEL: ctz128: 167; CHECK-NEXT: .functype ctz128 (i32, i64, i64) -> (){{$}} 168; CHECK: i64.ctz 169; CHECK: i64.ctz 170; CHECK: return{{$}} 171define i128 @ctz128(i128 %x) { 172 %a = call i128 @llvm.cttz.i128(i128 %x, i1 false) 173 ret i128 %a 174} 175 176; CHECK-LABEL: ctz128_zero_undef: 177; CHECK-NEXT: .functype ctz128_zero_undef (i32, i64, i64) -> (){{$}} 178; CHECK: i64.ctz 179; CHECK: i64.ctz 180; CHECK: return{{$}} 181define i128 @ctz128_zero_undef(i128 %x) { 182 %a = call i128 @llvm.cttz.i128(i128 %x, i1 true) 183 ret i128 %a 184} 185 186; CHECK-LABEL: popcnt128: 187; CHECK-NEXT: .functype popcnt128 (i32, i64, i64) -> (){{$}} 188; CHECK: i64.popcnt 189; CHECK: i64.popcnt 190; CHECK: return{{$}} 191define i128 @popcnt128(i128 %x) { 192 %a = call i128 @llvm.ctpop.i128(i128 %x) 193 ret i128 %a 194} 195 196; CHECK-LABEL: eqz128: 197; CHECK-NEXT: .functype eqz128 (i64, i64) -> (i32){{$}} 198; CHECK: i64.or 199; CHECK: i64.eqz 200; CHECK: return $ 201define i32 @eqz128(i128 %x) { 202 %a = icmp eq i128 %x, 0 203 %b = zext i1 %a to i32 204 ret i32 %b 205} 206 207; CHECK-LABEL: rotl: 208; CHECK-NEXT: .functype rotl (i32, i64, i64, i64, i64) -> (){{$}} 209; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 210; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 211; CHECK: return{{$}} 212define i128 @rotl(i128 %x, i128 %y) { 213 %z = sub i128 128, %y 214 %b = shl i128 %x, %y 215 %c = lshr i128 %x, %z 216 %d = or i128 %b, %c 217 ret i128 %d 218} 219 220; CHECK-LABEL: masked_rotl: 221; CHECK-NEXT: .functype masked_rotl (i32, i64, i64, i64, i64) -> (){{$}} 222; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 223; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 224; CHECK: return{{$}} 225define i128 @masked_rotl(i128 %x, i128 %y) { 226 %a = and i128 %y, 127 227 %z = sub i128 128, %a 228 %b = shl i128 %x, %a 229 %c = lshr i128 %x, %z 230 %d = or i128 %b, %c 231 ret i128 %d 232} 233 234; CHECK-LABEL: rotr: 235; CHECK-NEXT: .functype rotr (i32, i64, i64, i64, i64) -> (){{$}} 236; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 237; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 238; CHECK: return{{$}} 239define i128 @rotr(i128 %x, i128 %y) { 240 %z = sub i128 128, %y 241 %b = lshr i128 %x, %y 242 %c = shl i128 %x, %z 243 %d = or i128 %b, %c 244 ret i128 %d 245} 246 247; CHECK-LABEL: masked_rotr: 248; CHECK-NEXT: .functype masked_rotr (i32, i64, i64, i64, i64) -> (){{$}} 249; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 250; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}} 251; CHECK: return{{$}} 252define i128 @masked_rotr(i128 %x, i128 %y) { 253 %a = and i128 %y, 127 254 %z = sub i128 128, %a 255 %b = lshr i128 %x, %a 256 %c = shl i128 %x, %z 257 %d = or i128 %b, %c 258 ret i128 %d 259} 260