230 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 32; Test high-part i64->i128 multiplications on z17.3;4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z17 | FileCheck %s5 6; Check zero-extended multiplication in which only the high part is used.7define i64 @f1(i64 %dummy, i64 %a, i64 %b) {8; CHECK-LABEL: f1:9; CHECK: # %bb.0:10; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q11; CHECK-NEXT: mlgr %r2, %r412; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q13; CHECK-NEXT: br %r1414 %ax = zext i64 %a to i12815 %bx = zext i64 %b to i12816 %mulx = mul i128 %ax, %bx17 %highx = lshr i128 %mulx, 6418 %high = trunc i128 %highx to i6419 ret i64 %high20}21 22; Check sign-extended multiplication in which only the high part is used.23define i64 @f2(i64 %dummy, i64 %a, i64 %b) {24; CHECK-LABEL: f2:25; CHECK: # %bb.0:26; CHECK-NEXT: mgrk %r2, %r3, %r427; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q28; CHECK-NEXT: br %r1429 %ax = sext i64 %a to i12830 %bx = sext i64 %b to i12831 %mulx = mul i128 %ax, %bx32 %highx = lshr i128 %mulx, 6433 %high = trunc i128 %highx to i6434 ret i64 %high35}36 37; Check zero-extended multiplication in which only part of the high half38; is used. FIXME: Should use MLGR as well.39define i64 @f3(i64 %dummy, i64 %a, i64 %b) {40; CHECK-LABEL: f3:41; CHECK: # %bb.0:42; CHECK-NEXT: vgbm %v0, 043; CHECK-NEXT: vgbm %v1, 044; CHECK-NEXT: vlvgg %v1, %r3, 145; CHECK-NEXT: vlvgg %v0, %r4, 146; CHECK-NEXT: vmlq %v0, %v1, %v047; CHECK-NEXT: vrepib %v1, 6748; CHECK-NEXT: vsrlb %v0, %v0, %v149; CHECK-NEXT: vsrl %v0, %v0, %v150; CHECK-NEXT: vlgvg %r2, %v0, 151; CHECK-NEXT: br %r1452 %ax = zext i64 %a to i12853 %bx = zext i64 %b to i12854 %mulx = mul i128 %ax, %bx55 %highx = lshr i128 %mulx, 6756 %high = trunc i128 %highx to i6457 ret i64 %high58}59 60; Check zero-extended multiplication in which the result is split into61; high and low halves. FIXME: Should use MLGR as well.62define i64 @f4(i64 %dummy, i64 %a, i64 %b) {63; CHECK-LABEL: f4:64; CHECK: # %bb.0:65; CHECK-NEXT: vgbm %v0, 066; CHECK-NEXT: vgbm %v1, 067; CHECK-NEXT: vlvgg %v1, %r3, 168; CHECK-NEXT: vlvgg %v0, %r4, 169; CHECK-NEXT: vmlq %v0, %v1, %v070; CHECK-NEXT: vrepib %v1, 6471; CHECK-NEXT: vsrlb %v1, %v0, %v172; CHECK-NEXT: vo %v0, %v1, %v073; CHECK-NEXT: vlgvg %r2, %v0, 174; CHECK-NEXT: br %r1475 %ax = zext i64 %a to i12876 %bx = zext i64 %b to i12877 %mulx = mul i128 %ax, %bx78 %highx = lshr i128 %mulx, 6479 %high = trunc i128 %highx to i6480 %low = trunc i128 %mulx to i6481 %or = or i64 %high, %low82 ret i64 %or83}84 85; Check division by a constant, which should use multiplication instead.86define i64 @f5(i64 %dummy, i64 %a) {87; CHECK-LABEL: f5:88; CHECK: # %bb.0:89; CHECK-NEXT: llihf %r0, 178202857090; CHECK-NEXT: oilf %r0, 59865022391; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q92; CHECK-NEXT: mlgr %r2, %r093; CHECK-NEXT: srlg %r2, %r2, 994; CHECK-NEXT: br %r1495 %res = udiv i64 %a, 123496 ret i64 %res97}98 99; Check MLG with no displacement.100define i64 @f6(i64 %dummy, i64 %a, ptr %src) {101; CHECK-LABEL: f6:102; CHECK: # %bb.0:103; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q104; CHECK-NEXT: mlg %r2, 0(%r4)105; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q106; CHECK-NEXT: br %r14107 %b = load i64, ptr %src108 %ax = zext i64 %a to i128109 %bx = zext i64 %b to i128110 %mulx = mul i128 %ax, %bx111 %highx = lshr i128 %mulx, 64112 %high = trunc i128 %highx to i64113 ret i64 %high114}115 116; Check the high end of the aligned MLG range.117define i64 @f7(i64 %dummy, i64 %a, ptr %src) {118; CHECK-LABEL: f7:119; CHECK: # %bb.0:120; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q121; CHECK-NEXT: mlg %r2, 524280(%r4)122; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q123; CHECK-NEXT: br %r14124 %ptr = getelementptr i64, ptr %src, i64 65535125 %b = load i64, ptr %ptr126 %ax = zext i64 %a to i128127 %bx = zext i64 %b to i128128 %mulx = mul i128 %ax, %bx129 %highx = lshr i128 %mulx, 64130 %high = trunc i128 %highx to i64131 ret i64 %high132}133 134; Check the next doubleword up, which requires separate address logic.135; Other sequences besides this one would be OK.136define i64 @f8(i64 %dummy, i64 %a, ptr %src) {137; CHECK-LABEL: f8:138; CHECK: # %bb.0:139; CHECK-NEXT: agfi %r4, 524288140; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q141; CHECK-NEXT: mlg %r2, 0(%r4)142; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q143; CHECK-NEXT: br %r14144 %ptr = getelementptr i64, ptr %src, i64 65536145 %b = load i64, ptr %ptr146 %ax = zext i64 %a to i128147 %bx = zext i64 %b to i128148 %mulx = mul i128 %ax, %bx149 %highx = lshr i128 %mulx, 64150 %high = trunc i128 %highx to i64151 ret i64 %high152}153 154; Check the high end of the negative aligned MLG range.155define i64 @f9(i64 %dummy, i64 %a, ptr %src) {156; CHECK-LABEL: f9:157; CHECK: # %bb.0:158; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q159; CHECK-NEXT: mlg %r2, -8(%r4)160; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q161; CHECK-NEXT: br %r14162 %ptr = getelementptr i64, ptr %src, i64 -1163 %b = load i64, ptr %ptr164 %ax = zext i64 %a to i128165 %bx = zext i64 %b to i128166 %mulx = mul i128 %ax, %bx167 %highx = lshr i128 %mulx, 64168 %high = trunc i128 %highx to i64169 ret i64 %high170}171 172; Check the low end of the MLG range.173define i64 @f10(i64 %dummy, i64 %a, ptr %src) {174; CHECK-LABEL: f10:175; CHECK: # %bb.0:176; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q177; CHECK-NEXT: mlg %r2, -524288(%r4)178; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q179; CHECK-NEXT: br %r14180 %ptr = getelementptr i64, ptr %src, i64 -65536181 %b = load i64, ptr %ptr182 %ax = zext i64 %a to i128183 %bx = zext i64 %b to i128184 %mulx = mul i128 %ax, %bx185 %highx = lshr i128 %mulx, 64186 %high = trunc i128 %highx to i64187 ret i64 %high188}189 190; Check the next doubleword down, which needs separate address logic.191; Other sequences besides this one would be OK.192define i64 @f11(ptr %dest, i64 %a, ptr %src) {193; CHECK-LABEL: f11:194; CHECK: # %bb.0:195; CHECK-NEXT: agfi %r4, -524296196; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q197; CHECK-NEXT: mlg %r2, 0(%r4)198; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q199; CHECK-NEXT: br %r14200 %ptr = getelementptr i64, ptr %src, i64 -65537201 %b = load i64, ptr %ptr202 %ax = zext i64 %a to i128203 %bx = zext i64 %b to i128204 %mulx = mul i128 %ax, %bx205 %highx = lshr i128 %mulx, 64206 %high = trunc i128 %highx to i64207 ret i64 %high208}209 210; Check that MLG allows an index.211define i64 @f12(ptr %dest, i64 %a, i64 %src, i64 %index) {212; CHECK-LABEL: f12:213; CHECK: # %bb.0:214; CHECK-NEXT: # kill: def $r3d killed $r3d def $r2q215; CHECK-NEXT: mlg %r2, 524287(%r5,%r4)216; CHECK-NEXT: # kill: def $r2d killed $r2d killed $r2q217; CHECK-NEXT: br %r14218 %add1 = add i64 %src, %index219 %add2 = add i64 %add1, 524287220 %ptr = inttoptr i64 %add2 to ptr221 %b = load i64, ptr %ptr222 %ax = zext i64 %a to i128223 %bx = zext i64 %b to i128224 %mulx = mul i128 %ax, %bx225 %highx = lshr i128 %mulx, 64226 %high = trunc i128 %highx to i64227 ret i64 %high228}229 230