Index: llvm/trunk/test/CodeGen/AArch64/arm64-bitfield-extract.ll =================================================================== --- llvm/trunk/test/CodeGen/AArch64/arm64-bitfield-extract.ll +++ llvm/trunk/test/CodeGen/AArch64/arm64-bitfield-extract.ll @@ -1,16 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -codegenprepare -mtriple=arm64-apple=ios -S -o - %s | FileCheck --check-prefix=OPT %s -; RUN: llc < %s -mtriple=arm64-eabi | FileCheck %s +; RUN: llc < %s -mtriple=arm64-eabi | FileCheck --check-prefix=LLC %s + %struct.X = type { i8, i8, [2 x i8] } %struct.Y = type { i32, i8 } %struct.Z = type { i8, i8, [2 x i8], i16 } %struct.A = type { i64, i8 } define void @foo(%struct.X* nocapture %x, %struct.Y* nocapture %y) nounwind optsize ssp { -; CHECK-LABEL: foo: -; CHECK: ubfx -; CHECK-NOT: and -; CHECK: ret - +; LLC-LABEL: foo: +; LLC: // %bb.0: +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: ubfx w8, w8, #3, #1 +; LLC-NEXT: strb w8, [x1, #4] +; LLC-NEXT: ret +; OPT-LABEL: @foo( +; OPT-NEXT: [[TMP:%.*]] = bitcast %struct.X* [[X:%.*]] to i32* +; OPT-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4 +; OPT-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_Y:%.*]], %struct.Y* [[Y:%.*]], i64 0, i32 1 +; OPT-NEXT: [[BF_CLEAR:%.*]] = lshr i32 [[TMP1]], 3 +; OPT-NEXT: [[BF_CLEAR_LOBIT:%.*]] = and i32 [[BF_CLEAR]], 1 +; OPT-NEXT: [[FROMBOOL:%.*]] = trunc i32 [[BF_CLEAR_LOBIT]] to i8 +; OPT-NEXT: store i8 [[FROMBOOL]], i8* [[B]], align 1 +; OPT-NEXT: ret void +; %tmp = bitcast %struct.X* %x to i32* %tmp1 = load i32, i32* %tmp, align 4 %b = getelementptr inbounds %struct.Y, %struct.Y* %y, i64 0, i32 1 @@ -22,8 +35,16 @@ } define i32 @baz(i64 %cav1.coerce) nounwind { -; CHECK-LABEL: baz: -; CHECK: sbfx w0, w0, #0, #4 +; LLC-LABEL: baz: +; LLC: // %bb.0: +; LLC-NEXT: sbfx w0, w0, #0, #4 +; LLC-NEXT: ret +; OPT-LABEL: @baz( +; OPT-NEXT: [[TMP:%.*]] = trunc i64 [[CAV1_COERCE:%.*]] to i32 +; OPT-NEXT: [[TMP1:%.*]] = shl i32 [[TMP]], 28 +; OPT-NEXT: [[BF_VAL_SEXT:%.*]] = ashr exact i32 [[TMP1]], 28 +; OPT-NEXT: ret i32 [[BF_VAL_SEXT]] +; %tmp = trunc i64 %cav1.coerce to i32 %tmp1 = shl i32 %tmp, 28 %bf.val.sext = ashr exact i32 %tmp1, 28 @@ -31,8 +52,16 @@ } define i32 @bar(i64 %cav1.coerce) nounwind { -; CHECK-LABEL: bar: -; CHECK: sbfx w0, w0, #4, #6 +; LLC-LABEL: bar: +; LLC: // %bb.0: +; LLC-NEXT: sbfx w0, w0, #4, #6 +; LLC-NEXT: ret +; OPT-LABEL: @bar( +; OPT-NEXT: [[TMP:%.*]] = trunc i64 [[CAV1_COERCE:%.*]] to i32 +; OPT-NEXT: [[CAV1_SROA_0_1_INSERT:%.*]] = shl i32 [[TMP]], 22 +; OPT-NEXT: [[TMP1:%.*]] = ashr i32 [[CAV1_SROA_0_1_INSERT]], 26 +; OPT-NEXT: ret i32 [[TMP1]] +; %tmp = trunc i64 %cav1.coerce to i32 %cav1.sroa.0.1.insert = shl i32 %tmp, 22 %tmp1 = ashr i32 %cav1.sroa.0.1.insert, 26 @@ -40,11 +69,21 @@ } define void @fct1(%struct.Z* nocapture %x, %struct.A* nocapture %y) nounwind optsize ssp { -; CHECK-LABEL: fct1: -; CHECK: ubfx x{{[0-9]+}}, x{{[0-9]+}} -; CHECK-NOT: and -; CHECK: ret - +; LLC-LABEL: fct1: +; LLC: // %bb.0: +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: ubfx x8, x8, #3, #1 +; LLC-NEXT: str x8, [x1] +; LLC-NEXT: ret +; OPT-LABEL: @fct1( +; OPT-NEXT: [[TMP:%.*]] = bitcast %struct.Z* [[X:%.*]] to i64* +; OPT-NEXT: [[TMP1:%.*]] = load i64, i64* [[TMP]], align 4 +; OPT-NEXT: [[B1:%.*]] = bitcast %struct.A* [[Y:%.*]] to i64* +; OPT-NEXT: [[BF_CLEAR:%.*]] = lshr i64 [[TMP1]], 3 +; OPT-NEXT: [[BF_CLEAR_LOBIT:%.*]] = and i64 [[BF_CLEAR]], 1 +; OPT-NEXT: store i64 [[BF_CLEAR_LOBIT]], i64* [[B1]], align 8 +; OPT-NEXT: ret void +; %tmp = bitcast %struct.Z* %x to i64* %tmp1 = load i64, i64* %tmp, align 4 %b = getelementptr inbounds %struct.A, %struct.A* %y, i64 0, i32 0 @@ -55,28 +94,53 @@ } define i64 @fct2(i64 %cav1.coerce) nounwind { -; CHECK-LABEL: fct2: -; CHECK: sbfx x0, x0, #0, #36 +; LLC-LABEL: fct2: +; LLC: // %bb.0: +; LLC-NEXT: sbfx x0, x0, #0, #36 +; LLC-NEXT: ret +; OPT-LABEL: @fct2( +; OPT-NEXT: [[TMP:%.*]] = shl i64 [[CAV1_COERCE:%.*]], 28 +; OPT-NEXT: [[BF_VAL_SEXT:%.*]] = ashr exact i64 [[TMP]], 28 +; OPT-NEXT: ret i64 [[BF_VAL_SEXT]] +; %tmp = shl i64 %cav1.coerce, 28 %bf.val.sext = ashr exact i64 %tmp, 28 ret i64 %bf.val.sext } define i64 @fct3(i64 %cav1.coerce) nounwind { -; CHECK-LABEL: fct3: -; CHECK: sbfx x0, x0, #4, #38 +; LLC-LABEL: fct3: +; LLC: // %bb.0: +; LLC-NEXT: sbfx x0, x0, #4, #38 +; LLC-NEXT: ret +; OPT-LABEL: @fct3( +; OPT-NEXT: [[CAV1_SROA_0_1_INSERT:%.*]] = shl i64 [[CAV1_COERCE:%.*]], 22 +; OPT-NEXT: [[TMP1:%.*]] = ashr i64 [[CAV1_SROA_0_1_INSERT]], 26 +; OPT-NEXT: ret i64 [[TMP1]] +; %cav1.sroa.0.1.insert = shl i64 %cav1.coerce, 22 %tmp1 = ashr i64 %cav1.sroa.0.1.insert, 26 ret i64 %tmp1 } define void @fct4(i64* nocapture %y, i64 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct4: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: bfxil x8, x1, #16, #24 +; LLC-NEXT: str x8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct4( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i64 [[TMP0]], -16777216 +; OPT-NEXT: [[SHR:%.*]] = lshr i64 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i64 [[SHR]], 16777215 +; OPT-NEXT: [[OR:%.*]] = or i64 [[AND]], [[AND1]] +; OPT-NEXT: store i64 [[OR]], i64* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct4: -; CHECK: ldr [[REG1:x[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], x1, #16, #24 -; CHECK-NEXT: str [[REG1]], -; CHECK-NEXT: ret %0 = load i64, i64* %y, align 8 %and = and i64 %0, -16777216 %shr = lshr i64 %x, 16 @@ -87,12 +151,23 @@ } define void @fct5(i32* nocapture %y, i32 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct5: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: bfxil w8, w1, #16, #3 +; LLC-NEXT: str w8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct5( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i32, i32* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i32 [[TMP0]], -8 +; OPT-NEXT: [[SHR:%.*]] = lshr i32 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i32 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i32 [[AND]], [[AND1]] +; OPT-NEXT: store i32 [[OR]], i32* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct5: -; CHECK: ldr [[REG1:w[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], w1, #16, #3 -; CHECK-NEXT: str [[REG1]], -; CHECK-NEXT: ret %0 = load i32, i32* %y, align 8 %and = and i32 %0, -8 %shr = lshr i32 %x, 16 @@ -104,14 +179,26 @@ ; Check if we can still catch bfm instruction when we drop some low bits define void @fct6(i32* nocapture %y, i32 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct6: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: bfxil w8, w1, #16, #3 +; LLC-NEXT: lsr w8, w8, #2 +; LLC-NEXT: str w8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct6( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i32, i32* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i32 [[TMP0]], -8 +; OPT-NEXT: [[SHR:%.*]] = lshr i32 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i32 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i32 [[AND]], [[AND1]] +; OPT-NEXT: [[SHR1:%.*]] = lshr i32 [[OR]], 2 +; OPT-NEXT: store i32 [[SHR1]], i32* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct6: -; CHECK: ldr [[REG1:w[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], w1, #16, #3 ; lsr is an alias of ubfm -; CHECK-NEXT: lsr [[REG2:w[0-9]+]], [[REG1]], #2 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i32, i32* %y, align 8 %and = and i32 %0, -8 %shr = lshr i32 %x, 16 @@ -125,14 +212,26 @@ ; Check if we can still catch bfm instruction when we drop some high bits define void @fct7(i32* nocapture %y, i32 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct7: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: bfxil w8, w1, #16, #3 +; LLC-NEXT: lsl w8, w8, #2 +; LLC-NEXT: str w8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct7( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i32, i32* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i32 [[TMP0]], -8 +; OPT-NEXT: [[SHR:%.*]] = lshr i32 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i32 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i32 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i32 [[OR]], 2 +; OPT-NEXT: store i32 [[SHL]], i32* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct7: -; CHECK: ldr [[REG1:w[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], w1, #16, #3 ; lsl is an alias of ubfm -; CHECK-NEXT: lsl [[REG2:w[0-9]+]], [[REG1]], #2 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i32, i32* %y, align 8 %and = and i32 %0, -8 %shr = lshr i32 %x, 16 @@ -147,14 +246,26 @@ ; Check if we can still catch bfm instruction when we drop some low bits ; (i64 version) define void @fct8(i64* nocapture %y, i64 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct8: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: bfxil x8, x1, #16, #3 +; LLC-NEXT: lsr x8, x8, #2 +; LLC-NEXT: str x8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct8( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i64 [[TMP0]], -8 +; OPT-NEXT: [[SHR:%.*]] = lshr i64 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i64 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i64 [[AND]], [[AND1]] +; OPT-NEXT: [[SHR1:%.*]] = lshr i64 [[OR]], 2 +; OPT-NEXT: store i64 [[SHR1]], i64* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct8: -; CHECK: ldr [[REG1:x[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], x1, #16, #3 ; lsr is an alias of ubfm -; CHECK-NEXT: lsr [[REG2:x[0-9]+]], [[REG1]], #2 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i64, i64* %y, align 8 %and = and i64 %0, -8 %shr = lshr i64 %x, 16 @@ -169,14 +280,26 @@ ; Check if we can still catch bfm instruction when we drop some high bits ; (i64 version) define void @fct9(i64* nocapture %y, i64 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct9: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: bfxil x8, x1, #16, #3 +; LLC-NEXT: lsl x8, x8, #2 +; LLC-NEXT: str x8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct9( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i64 [[TMP0]], -8 +; OPT-NEXT: [[SHR:%.*]] = lshr i64 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i64 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i64 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i64 [[OR]], 2 +; OPT-NEXT: store i64 [[SHL]], i64* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct9: -; CHECK: ldr [[REG1:x[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], x1, #16, #3 ; lsr is an alias of ubfm -; CHECK-NEXT: lsl [[REG2:x[0-9]+]], [[REG1]], #2 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i64, i64* %y, align 8 %and = and i64 %0, -8 %shr = lshr i64 %x, 16 @@ -190,14 +313,25 @@ ; Check if we can catch bfm instruction when lsb is 0 (i.e., no lshr) ; (i32 version) define void @fct10(i32* nocapture %y, i32 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct10: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: bfxil w8, w1, #0, #3 +; LLC-NEXT: lsl w8, w8, #2 +; LLC-NEXT: str w8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct10( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i32, i32* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i32 [[TMP0]], -8 +; OPT-NEXT: [[AND1:%.*]] = and i32 [[X:%.*]], 7 +; OPT-NEXT: [[OR:%.*]] = or i32 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i32 [[OR]], 2 +; OPT-NEXT: store i32 [[SHL]], i32* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct10: -; CHECK: ldr [[REG1:w[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], w1, #0, #3 ; lsl is an alias of ubfm -; CHECK-NEXT: lsl [[REG2:w[0-9]+]], [[REG1]], #2 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i32, i32* %y, align 8 %and = and i32 %0, -8 %and1 = and i32 %x, 7 @@ -210,14 +344,25 @@ ; Check if we can catch bfm instruction when lsb is 0 (i.e., no lshr) ; (i64 version) define void @fct11(i64* nocapture %y, i64 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct11: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: bfxil x8, x1, #0, #3 +; LLC-NEXT: lsl x8, x8, #2 +; LLC-NEXT: str x8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct11( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i64 [[TMP0]], -8 +; OPT-NEXT: [[AND1:%.*]] = and i64 [[X:%.*]], 7 +; OPT-NEXT: [[OR:%.*]] = or i64 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i64 [[OR]], 2 +; OPT-NEXT: store i64 [[SHL]], i64* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct11: -; CHECK: ldr [[REG1:x[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], x1, #0, #3 ; lsl is an alias of ubfm -; CHECK-NEXT: lsl [[REG2:x[0-9]+]], [[REG1]], #2 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i64, i64* %y, align 8 %and = and i64 %0, -8 %and1 = and i64 %x, 7 @@ -228,9 +373,15 @@ } define zeroext i1 @fct12bis(i32 %tmp2) unnamed_addr nounwind ssp align 2 { -; CHECK-LABEL: fct12bis: -; CHECK-NOT: and -; CHECK: ubfx w0, w0, #11, #1 +; LLC-LABEL: fct12bis: +; LLC: // %bb.0: +; LLC-NEXT: ubfx w0, w0, #11, #1 +; LLC-NEXT: ret +; OPT-LABEL: @fct12bis( +; OPT-NEXT: [[AND_I_I:%.*]] = and i32 [[TMP2:%.*]], 2048 +; OPT-NEXT: [[TOBOOL_I_I:%.*]] = icmp ne i32 [[AND_I_I]], 0 +; OPT-NEXT: ret i1 [[TOBOOL_I_I]] +; %and.i.i = and i32 %tmp2, 2048 %tobool.i.i = icmp ne i32 %and.i.i, 0 ret i1 %tobool.i.i @@ -239,14 +390,27 @@ ; Check if we can still catch bfm instruction when we drop some high bits ; and some low bits define void @fct12(i32* nocapture %y, i32 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct12: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: bfxil w8, w1, #16, #3 +; LLC-NEXT: ubfx w8, w8, #2, #28 +; LLC-NEXT: str w8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct12( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i32, i32* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i32 [[TMP0]], -8 +; OPT-NEXT: [[SHR:%.*]] = lshr i32 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i32 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i32 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i32 [[OR]], 2 +; OPT-NEXT: [[SHR2:%.*]] = lshr i32 [[SHL]], 4 +; OPT-NEXT: store i32 [[SHR2]], i32* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct12: -; CHECK: ldr [[REG1:w[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], w1, #16, #3 ; lsr is an alias of ubfm -; CHECK-NEXT: ubfx [[REG2:w[0-9]+]], [[REG1]], #2, #28 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i32, i32* %y, align 8 %and = and i32 %0, -8 %shr = lshr i32 %x, 16 @@ -262,14 +426,27 @@ ; and some low bits ; (i64 version) define void @fct13(i64* nocapture %y, i64 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct13: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: bfxil x8, x1, #16, #3 +; LLC-NEXT: ubfx x8, x8, #2, #60 +; LLC-NEXT: str x8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct13( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i64 [[TMP0]], -8 +; OPT-NEXT: [[SHR:%.*]] = lshr i64 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i64 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i64 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i64 [[OR]], 2 +; OPT-NEXT: [[SHR2:%.*]] = lshr i64 [[SHL]], 4 +; OPT-NEXT: store i64 [[SHR2]], i64* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct13: -; CHECK: ldr [[REG1:x[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], x1, #16, #3 ; lsr is an alias of ubfm -; CHECK-NEXT: ubfx [[REG2:x[0-9]+]], [[REG1]], #2, #60 -; CHECK-NEXT: str [[REG2]], -; CHECK-NEXT: ret %0 = load i64, i64* %y, align 8 %and = and i64 %0, -8 %shr = lshr i64 %x, 16 @@ -285,17 +462,34 @@ ; Check if we can still catch bfm instruction when we drop some high bits ; and some low bits define void @fct14(i32* nocapture %y, i32 %x, i32 %x1) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct14: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: bfxil w8, w1, #16, #8 +; LLC-NEXT: lsr w8, w8, #4 +; LLC-NEXT: bfxil w8, w2, #5, #3 +; LLC-NEXT: lsl w8, w8, #2 +; LLC-NEXT: str w8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct14( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i32, i32* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i32 [[TMP0]], -256 +; OPT-NEXT: [[SHR:%.*]] = lshr i32 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i32 [[SHR]], 255 +; OPT-NEXT: [[OR:%.*]] = or i32 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = lshr i32 [[OR]], 4 +; OPT-NEXT: [[AND2:%.*]] = and i32 [[SHL]], -8 +; OPT-NEXT: [[SHR1:%.*]] = lshr i32 [[X1:%.*]], 5 +; OPT-NEXT: [[AND3:%.*]] = and i32 [[SHR1]], 7 +; OPT-NEXT: [[OR1:%.*]] = or i32 [[AND2]], [[AND3]] +; OPT-NEXT: [[SHL1:%.*]] = shl i32 [[OR1]], 2 +; OPT-NEXT: store i32 [[SHL1]], i32* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct14: -; CHECK: ldr [[REG1:w[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], w1, #16, #8 ; lsr is an alias of ubfm -; CHECK-NEXT: lsr [[REG2:w[0-9]+]], [[REG1]], #4 -; CHECK-NEXT: bfxil [[REG2]], w2, #5, #3 ; lsl is an alias of ubfm -; CHECK-NEXT: lsl [[REG3:w[0-9]+]], [[REG2]], #2 -; CHECK-NEXT: str [[REG3]], -; CHECK-NEXT: ret %0 = load i32, i32* %y, align 8 %and = and i32 %0, -256 %shr = lshr i32 %x, 16 @@ -315,17 +509,34 @@ ; and some low bits ; (i64 version) define void @fct15(i64* nocapture %y, i64 %x, i64 %x1) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct15: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: bfxil x8, x1, #16, #8 +; LLC-NEXT: lsr x8, x8, #4 +; LLC-NEXT: bfxil x8, x2, #5, #3 +; LLC-NEXT: lsl x8, x8, #2 +; LLC-NEXT: str x8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct15( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i64 [[TMP0]], -256 +; OPT-NEXT: [[SHR:%.*]] = lshr i64 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i64 [[SHR]], 255 +; OPT-NEXT: [[OR:%.*]] = or i64 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = lshr i64 [[OR]], 4 +; OPT-NEXT: [[AND2:%.*]] = and i64 [[SHL]], -8 +; OPT-NEXT: [[SHR1:%.*]] = lshr i64 [[X1:%.*]], 5 +; OPT-NEXT: [[AND3:%.*]] = and i64 [[SHR1]], 7 +; OPT-NEXT: [[OR1:%.*]] = or i64 [[AND2]], [[AND3]] +; OPT-NEXT: [[SHL1:%.*]] = shl i64 [[OR1]], 2 +; OPT-NEXT: store i64 [[SHL1]], i64* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct15: -; CHECK: ldr [[REG1:x[0-9]+]], -; CHECK-NEXT: bfxil [[REG1]], x1, #16, #8 ; lsr is an alias of ubfm -; CHECK-NEXT: lsr [[REG2:x[0-9]+]], [[REG1]], #4 -; CHECK-NEXT: bfxil [[REG2]], x2, #5, #3 ; lsl is an alias of ubfm -; CHECK-NEXT: lsl [[REG3:x[0-9]+]], [[REG2]], #2 -; CHECK-NEXT: str [[REG3]], -; CHECK-NEXT: ret %0 = load i64, i64* %y, align 8 %and = and i64 %0, -256 %shr = lshr i64 %x, 16 @@ -344,19 +555,32 @@ ; Check if we can still catch bfm instruction when we drop some high bits ; and some low bits and a masking operation has to be kept define void @fct16(i32* nocapture %y, i32 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct16: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr w8, [x0] +; LLC-NEXT: mov w9, #33120 +; LLC-NEXT: movk w9, #26, lsl #16 +; LLC-NEXT: and w8, w8, w9 +; LLC-NEXT: bfxil w8, w1, #16, #3 +; LLC-NEXT: ubfx w8, w8, #2, #28 +; LLC-NEXT: str w8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct16( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i32, i32* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i32 [[TMP0]], 1737056 +; OPT-NEXT: [[SHR:%.*]] = lshr i32 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i32 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i32 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i32 [[OR]], 2 +; OPT-NEXT: [[SHR2:%.*]] = lshr i32 [[SHL]], 4 +; OPT-NEXT: store i32 [[SHR2]], i32* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct16: -; CHECK: ldr [[REG1:w[0-9]+]], ; Create the constant -; CHECK: mov [[REGCST:w[0-9]+]], #33120 -; CHECK: movk [[REGCST]], #26, lsl #16 ; Do the masking -; CHECK: and [[REG2:w[0-9]+]], [[REG1]], [[REGCST]] -; CHECK-NEXT: bfxil [[REG2]], w1, #16, #3 ; lsr is an alias of ubfm -; CHECK-NEXT: ubfx [[REG3:w[0-9]+]], [[REG2]], #2, #28 -; CHECK-NEXT: str [[REG3]], -; CHECK-NEXT: ret %0 = load i32, i32* %y, align 8 %and = and i32 %0, 1737056 %shr = lshr i32 %x, 16 @@ -373,19 +597,32 @@ ; and some low bits and a masking operation has to be kept ; (i64 version) define void @fct17(i64* nocapture %y, i64 %x) nounwind optsize inlinehint ssp { +; LLC-LABEL: fct17: +; LLC: // %bb.0: // %entry +; LLC-NEXT: ldr x8, [x0] +; LLC-NEXT: mov w9, #33120 +; LLC-NEXT: movk w9, #26, lsl #16 +; LLC-NEXT: and x8, x8, x9 +; LLC-NEXT: bfxil x8, x1, #16, #3 +; LLC-NEXT: ubfx x8, x8, #2, #60 +; LLC-NEXT: str x8, [x0] +; LLC-NEXT: ret +; OPT-LABEL: @fct17( +; OPT-NEXT: entry: +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[Y:%.*]], align 8 +; OPT-NEXT: [[AND:%.*]] = and i64 [[TMP0]], 1737056 +; OPT-NEXT: [[SHR:%.*]] = lshr i64 [[X:%.*]], 16 +; OPT-NEXT: [[AND1:%.*]] = and i64 [[SHR]], 7 +; OPT-NEXT: [[OR:%.*]] = or i64 [[AND]], [[AND1]] +; OPT-NEXT: [[SHL:%.*]] = shl i64 [[OR]], 2 +; OPT-NEXT: [[SHR2:%.*]] = lshr i64 [[SHL]], 4 +; OPT-NEXT: store i64 [[SHR2]], i64* [[Y]], align 8 +; OPT-NEXT: ret void +; entry: -; CHECK-LABEL: fct17: -; CHECK: ldr [[REG1:x[0-9]+]], ; Create the constant -; CHECK: mov w[[REGCST:[0-9]+]], #33120 -; CHECK: movk w[[REGCST]], #26, lsl #16 ; Do the masking -; CHECK: and [[REG2:x[0-9]+]], [[REG1]], x[[REGCST]] -; CHECK-NEXT: bfxil [[REG2]], x1, #16, #3 ; lsr is an alias of ubfm -; CHECK-NEXT: ubfx [[REG3:x[0-9]+]], [[REG2]], #2, #60 -; CHECK-NEXT: str [[REG3]], -; CHECK-NEXT: ret %0 = load i64, i64* %y, align 8 %and = and i64 %0, 1737056 %shr = lshr i64 %x, 16 @@ -398,8 +635,17 @@ } define i64 @fct18(i32 %xor72) nounwind ssp { -; CHECK-LABEL: fct18: -; CHECK: ubfx x0, x0, #9, #8 +; LLC-LABEL: fct18: +; LLC: // %bb.0: +; LLC-NEXT: // kill: def $w0 killed $w0 def $x0 +; LLC-NEXT: ubfx x0, x0, #9, #8 +; LLC-NEXT: ret +; OPT-LABEL: @fct18( +; OPT-NEXT: [[SHR81:%.*]] = lshr i32 [[XOR72:%.*]], 9 +; OPT-NEXT: [[CONV82:%.*]] = zext i32 [[SHR81]] to i64 +; OPT-NEXT: [[RESULT:%.*]] = and i64 [[CONV82]], 255 +; OPT-NEXT: ret i64 [[RESULT]] +; %shr81 = lshr i32 %xor72, 9 %conv82 = zext i32 %shr81 to i64 %result = and i64 %conv82, 255 @@ -411,7 +657,78 @@ ; Function Attrs: nounwind readonly ssp define i32 @fct19(i64 %arg1) nounwind readonly ssp { -; CHECK-LABEL: fct19: +; LLC-LABEL: fct19: +; LLC: // %bb.0: // %entry +; LLC-NEXT: lsr x8, x0, #48 +; LLC-NEXT: cbz x8, .LBB22_2 +; LLC-NEXT: // %bb.1: // %if.then +; LLC-NEXT: adrp x9, first_ones +; LLC-NEXT: add x9, x9, :lo12:first_ones +; LLC-NEXT: ldrb w0, [x9, x8] +; LLC-NEXT: ret +; LLC-NEXT: .LBB22_2: // %if.end +; LLC-NEXT: ubfx x8, x0, #32, #16 +; LLC-NEXT: cbz w8, .LBB22_4 +; LLC-NEXT: // %bb.3: // %if.then7 +; LLC-NEXT: adrp x9, first_ones +; LLC-NEXT: add x9, x9, :lo12:first_ones +; LLC-NEXT: ldrb w8, [x9, x8] +; LLC-NEXT: add w0, w8, #16 // =16 +; LLC-NEXT: ret +; LLC-NEXT: .LBB22_4: // %if.end13 +; LLC-NEXT: ubfx x8, x0, #16, #16 +; LLC-NEXT: cbz w8, .LBB22_6 +; LLC-NEXT: // %bb.5: // %if.then17 +; LLC-NEXT: adrp x9, first_ones +; LLC-NEXT: add x9, x9, :lo12:first_ones +; LLC-NEXT: ldrb w8, [x9, x8] +; LLC-NEXT: add w0, w8, #32 // =32 +; LLC-NEXT: ret +; LLC-NEXT: .LBB22_6: +; LLC-NEXT: mov w0, #64 +; LLC-NEXT: ret +; OPT-LABEL: @fct19( +; OPT-NEXT: entry: +; OPT-NEXT: [[X_SROA_1_0_EXTRACT_SHIFT:%.*]] = lshr i64 [[ARG1:%.*]], 16 +; OPT-NEXT: [[X_SROA_1_0_EXTRACT_TRUNC:%.*]] = trunc i64 [[X_SROA_1_0_EXTRACT_SHIFT]] to i16 +; OPT-NEXT: [[X_SROA_5_0_EXTRACT_SHIFT:%.*]] = lshr i64 [[ARG1]], 48 +; OPT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X_SROA_5_0_EXTRACT_SHIFT]], 0 +; OPT-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] +; OPT: if.then: +; OPT-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds [65536 x i8], [65536 x i8]* @first_ones, i64 0, i64 [[X_SROA_5_0_EXTRACT_SHIFT]] +; OPT-NEXT: [[TMP0:%.*]] = load i8, i8* [[ARRAYIDX3]], align 1 +; OPT-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32 +; OPT-NEXT: br label [[RETURN:%.*]] +; OPT: if.end: +; OPT-NEXT: [[TMP1:%.*]] = lshr i64 [[ARG1]], 32 +; OPT-NEXT: [[X_SROA_3_0_EXTRACT_TRUNC:%.*]] = trunc i64 [[TMP1]] to i16 +; OPT-NEXT: [[TOBOOL6:%.*]] = icmp eq i16 [[X_SROA_3_0_EXTRACT_TRUNC]], 0 +; OPT-NEXT: br i1 [[TOBOOL6]], label [[IF_END13:%.*]], label [[IF_THEN7:%.*]] +; OPT: if.then7: +; OPT-NEXT: [[TMP2:%.*]] = lshr i64 [[ARG1]], 32 +; OPT-NEXT: [[IDXPROM10:%.*]] = and i64 [[TMP2]], 65535 +; OPT-NEXT: [[ARRAYIDX11:%.*]] = getelementptr inbounds [65536 x i8], [65536 x i8]* @first_ones, i64 0, i64 [[IDXPROM10]] +; OPT-NEXT: [[TMP3:%.*]] = load i8, i8* [[ARRAYIDX11]], align 1 +; OPT-NEXT: [[CONV12:%.*]] = zext i8 [[TMP3]] to i32 +; OPT-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV12]], 16 +; OPT-NEXT: br label [[RETURN]] +; OPT: if.end13: +; OPT-NEXT: [[TMP4:%.*]] = lshr i64 [[ARG1]], 16 +; OPT-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i16 +; OPT-NEXT: [[TOBOOL16:%.*]] = icmp eq i16 [[TMP5]], 0 +; OPT-NEXT: br i1 [[TOBOOL16]], label [[RETURN]], label [[IF_THEN17:%.*]] +; OPT: if.then17: +; OPT-NEXT: [[TMP6:%.*]] = lshr i64 [[ARG1]], 16 +; OPT-NEXT: [[IDXPROM20:%.*]] = and i64 [[TMP6]], 65535 +; OPT-NEXT: [[ARRAYIDX21:%.*]] = getelementptr inbounds [65536 x i8], [65536 x i8]* @first_ones, i64 0, i64 [[IDXPROM20]] +; OPT-NEXT: [[TMP7:%.*]] = load i8, i8* [[ARRAYIDX21]], align 1 +; OPT-NEXT: [[CONV22:%.*]] = zext i8 [[TMP7]] to i32 +; OPT-NEXT: [[ADD23:%.*]] = add nsw i32 [[CONV22]], 32 +; OPT-NEXT: br label [[RETURN]] +; OPT: return: +; OPT-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], [[IF_THEN]] ], [ [[ADD]], [[IF_THEN7]] ], [ [[ADD23]], [[IF_THEN17]] ], [ 64, [[IF_END13]] ] +; OPT-NEXT: ret i32 [[RETVAL_0]] +; entry: %x.sroa.1.0.extract.shift = lshr i64 %arg1, 16 %x.sroa.1.0.extract.trunc = trunc i64 %x.sroa.1.0.extract.shift to i16 @@ -426,22 +743,14 @@ %conv = zext i8 %0 to i32 br label %return -; OPT-LABEL: if.end if.end: ; preds = %entry -; OPT: lshr -; CHECK: ubfx [[REG1:x[0-9]+]], [[REG2:x[0-9]+]], #32, #16 %x.sroa.3.0.extract.trunc = trunc i64 %x.sroa.3.0.extract.shift to i16 %tobool6 = icmp eq i16 %x.sroa.3.0.extract.trunc, 0 -; CHECK: cbz br i1 %tobool6, label %if.end13, label %if.then7 -; OPT-LABEL: if.then7 if.then7: ; preds = %if.end -; OPT: lshr -; "and" should be combined to "ubfm" while "ubfm" should be removed by cse. -; So neither of them should be in the assemble code. -; CHECK-NOT: and -; CHECK-NOT: ubfm +; "and" should be combined to "ubfm" while "ubfm" should be removed by cse. +; So neither of them should be in the assemble code. %idxprom10 = and i64 %x.sroa.3.0.extract.shift, 65535 %arrayidx11 = getelementptr inbounds [65536 x i8], [65536 x i8]* @first_ones, i64 0, i64 %idxprom10 %1 = load i8, i8* %arrayidx11, align 1 @@ -449,22 +758,13 @@ %add = add nsw i32 %conv12, 16 br label %return -; OPT-LABEL: if.end13 if.end13: ; preds = %if.end -; OPT: lshr -; OPT: trunc -; CHECK: ubfx [[REG3:x[0-9]+]], [[REG4:x[0-9]+]], #16, #16 %tobool16 = icmp eq i16 %x.sroa.1.0.extract.trunc, 0 -; CHECK: cbz br i1 %tobool16, label %return, label %if.then17 -; OPT-LABEL: if.then17 if.then17: ; preds = %if.end13 -; OPT: lshr -; "and" should be combined to "ubfm" while "ubfm" should be removed by cse. -; So neither of them should be in the assemble code. -; CHECK-NOT: and -; CHECK-NOT: ubfm +; "and" should be combined to "ubfm" while "ubfm" should be removed by cse. +; So neither of them should be in the assemble code. %idxprom20 = and i64 %x.sroa.1.0.extract.shift, 65535 %arrayidx21 = getelementptr inbounds [65536 x i8], [65536 x i8]* @first_ones, i64 0, i64 %idxprom20 %2 = load i8, i8* %arrayidx21, align 1 @@ -473,39 +773,75 @@ br label %return return: ; preds = %if.end13, %if.then17, %if.then7, %if.then -; CHECK: ret %retval.0 = phi i32 [ %conv, %if.then ], [ %add, %if.then7 ], [ %add23, %if.then17 ], [ 64, %if.end13 ] ret i32 %retval.0 } ; Make sure we do not assert if the immediate in and is bigger than i64. ; PR19503. -; OPT-LABEL: @fct20 -; OPT: lshr -; OPT-NOT: lshr -; OPT: ret -; CHECK-LABEL: fct20: -; CHECK: ret define i80 @fct20(i128 %a, i128 %b) { +; LLC-LABEL: fct20: +; LLC: // %bb.0: // %entry +; LLC-NEXT: mov x12, #11776 +; LLC-NEXT: movk x12, #25856, lsl #16 +; LLC-NEXT: movk x12, #11077, lsl #32 +; LLC-NEXT: extr x8, x1, x0, #18 +; LLC-NEXT: lsr x9, x1, #18 +; LLC-NEXT: orr x10, x2, x3 +; LLC-NEXT: mov w11, #26220 +; LLC-NEXT: movk x12, #45, lsl #48 +; LLC-NEXT: and x11, x9, x11 +; LLC-NEXT: and x12, x8, x12 +; LLC-NEXT: cmp x10, #0 // =0 +; LLC-NEXT: csel x0, x12, x8, eq +; LLC-NEXT: csel x1, x11, x9, eq +; LLC-NEXT: ret +; OPT-LABEL: @fct20( +; OPT-NEXT: entry: +; OPT-NEXT: [[SHR:%.*]] = lshr i128 [[A:%.*]], 18 +; OPT-NEXT: [[CONV:%.*]] = trunc i128 [[SHR]] to i80 +; OPT-NEXT: [[TOBOOL:%.*]] = icmp eq i128 [[B:%.*]], 0 +; OPT-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[END:%.*]] +; OPT: then: +; OPT-NEXT: [[AND:%.*]] = and i128 [[SHR]], 483673642326615442599424 +; OPT-NEXT: [[CONV2:%.*]] = trunc i128 [[AND]] to i80 +; OPT-NEXT: br label [[END]] +; OPT: end: +; OPT-NEXT: [[CONV3:%.*]] = phi i80 [ [[CONV]], [[ENTRY:%.*]] ], [ [[CONV2]], [[THEN]] ] +; OPT-NEXT: ret i80 [[CONV3]] +; entry: %shr = lshr i128 %a, 18 %conv = trunc i128 %shr to i80 %tobool = icmp eq i128 %b, 0 br i1 %tobool, label %then, label %end -then: +then: %and = and i128 %shr, 483673642326615442599424 %conv2 = trunc i128 %and to i80 br label %end end: - %conv3 = phi i80 [%conv, %entry], [%conv2, %then] + %conv3 = phi i80 [%conv, %entry], [%conv2, %then] ret i80 %conv3 } ; Check if we can still catch UBFX when "AND" is used by SHL. -; CHECK-LABEL: fct21: -; CHECK: ubfx @arr = external global [8 x [64 x i64]] define i64 @fct21(i64 %x) { +; LLC-LABEL: fct21: +; LLC: // %bb.0: // %entry +; LLC-NEXT: adrp x9, arr +; LLC-NEXT: ubfx x8, x0, #4, #4 +; LLC-NEXT: add x9, x9, :lo12:arr +; LLC-NEXT: ldr x0, [x9, x8, lsl #3] +; LLC-NEXT: ret +; OPT-LABEL: @fct21( +; OPT-NEXT: entry: +; OPT-NEXT: [[SHR:%.*]] = lshr i64 [[X:%.*]], 4 +; OPT-NEXT: [[AND:%.*]] = and i64 [[SHR]], 15 +; OPT-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [8 x [64 x i64]], [8 x [64 x i64]]* @arr, i64 0, i64 0, i64 [[AND]] +; OPT-NEXT: [[TMP0:%.*]] = load i64, i64* [[ARRAYIDX]], align 8 +; OPT-NEXT: ret i64 [[TMP0]] +; entry: %shr = lshr i64 %x, 4 %and = and i64 %shr, 15 @@ -515,18 +851,30 @@ } define i16 @test_ignored_rightbits(i32 %dst, i32 %in) { -; CHECK-LABEL: test_ignored_rightbits: - +; LLC-LABEL: test_ignored_rightbits: +; LLC: // %bb.0: +; LLC-NEXT: and w0, w0, #0x7 +; LLC-NEXT: bfi w0, w1, #3, #4 +; LLC-NEXT: bfi w0, w0, #8, #7 +; LLC-NEXT: ret +; OPT-LABEL: @test_ignored_rightbits( +; OPT-NEXT: [[POSITIONED_FIELD:%.*]] = shl i32 [[IN:%.*]], 3 +; OPT-NEXT: [[POSITIONED_MASKED_FIELD:%.*]] = and i32 [[POSITIONED_FIELD]], 120 +; OPT-NEXT: [[MASKED_DST:%.*]] = and i32 [[DST:%.*]], 7 +; OPT-NEXT: [[INSERTION:%.*]] = or i32 [[MASKED_DST]], [[POSITIONED_MASKED_FIELD]] +; OPT-NEXT: [[SHL16:%.*]] = shl i32 [[INSERTION]], 8 +; OPT-NEXT: [[OR18:%.*]] = or i32 [[SHL16]], [[INSERTION]] +; OPT-NEXT: [[CONV19:%.*]] = trunc i32 [[OR18]] to i16 +; OPT-NEXT: ret i16 [[CONV19]] +; %positioned_field = shl i32 %in, 3 %positioned_masked_field = and i32 %positioned_field, 120 %masked_dst = and i32 %dst, 7 %insertion = or i32 %masked_dst, %positioned_masked_field -; CHECK: {{bfm|bfi|bfxil}} %shl16 = shl i32 %insertion, 8 %or18 = or i32 %shl16, %insertion %conv19 = trunc i32 %or18 to i16 -; CHECK: bfi {{w[0-9]+}}, {{w[0-9]+}}, #8, #7 ret i16 %conv19 } @@ -534,12 +882,37 @@ ; The following test excercises the case where we have a BFI ; instruction with the same input in both operands. We need to ; track the useful bits through both operands. -; CHECK-LABEL: sameOperandBFI -; CHECK: lsr -; CHECK: and -; CHECK: bfi -; CHECK: bfi define void @sameOperandBFI(i64 %src, i64 %src2, i16 *%ptr) { +; LLC-LABEL: sameOperandBFI: +; LLC: // %bb.0: // %entry +; LLC-NEXT: cbnz wzr, .LBB26_2 +; LLC-NEXT: // %bb.1: // %if.else +; LLC-NEXT: lsr x8, x0, #47 +; LLC-NEXT: and w9, w1, #0x3 +; LLC-NEXT: bfi w9, w8, #2, #2 +; LLC-NEXT: bfi w9, w9, #4, #4 +; LLC-NEXT: strh w9, [x2] +; LLC-NEXT: .LBB26_2: // %end +; LLC-NEXT: ret +; OPT-LABEL: @sameOperandBFI( +; OPT-NEXT: entry: +; OPT-NEXT: [[SHR47:%.*]] = lshr i64 [[SRC:%.*]], 47 +; OPT-NEXT: [[SRC2_TRUNC:%.*]] = trunc i64 [[SRC2:%.*]] to i32 +; OPT-NEXT: br i1 undef, label [[END:%.*]], label [[IF_ELSE:%.*]] +; OPT: if.else: +; OPT-NEXT: [[AND3:%.*]] = and i32 [[SRC2_TRUNC]], 3 +; OPT-NEXT: [[SHL2:%.*]] = shl nuw nsw i64 [[SHR47]], 2 +; OPT-NEXT: [[SHL2_TRUNC:%.*]] = trunc i64 [[SHL2]] to i32 +; OPT-NEXT: [[AND12:%.*]] = and i32 [[SHL2_TRUNC]], 12 +; OPT-NEXT: [[BFISOURCE:%.*]] = or i32 [[AND3]], [[AND12]] +; OPT-NEXT: [[BFIRHS:%.*]] = shl nuw nsw i32 [[BFISOURCE]], 4 +; OPT-NEXT: [[BFI:%.*]] = or i32 [[BFIRHS]], [[BFISOURCE]] +; OPT-NEXT: [[BFITRUNC:%.*]] = trunc i32 [[BFI]] to i16 +; OPT-NEXT: store i16 [[BFITRUNC]], i16* [[PTR:%.*]], align 4 +; OPT-NEXT: br label [[END]] +; OPT: end: +; OPT-NEXT: ret void +; entry: %shr47 = lshr i64 %src, 47 %src2.trunc = trunc i64 %src2 to i32 Index: llvm/trunk/utils/UpdateTestChecks/asm.py =================================================================== --- llvm/trunk/utils/UpdateTestChecks/asm.py +++ llvm/trunk/utils/UpdateTestChecks/asm.py @@ -206,6 +206,7 @@ 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 'i386': (scrub_asm_x86, ASM_FUNCTION_X86_RE), + 'arm64-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 'aarch64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 'r600': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE), 'amdgcn': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE),