| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes='require<profile-summary>,function(codegenprepare)' -mtriple=arm64-apple=ios -S -o - %s | FileCheck --check-prefix=OPT %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(ptr nocapture %x, ptr nocapture %y) nounwind optsize ssp { |
| ; 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: [[TMP1:%.*]] = load i32, ptr [[X:%.*]], align 4 |
| ; OPT-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_Y:%.*]], ptr [[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]], ptr [[B]], align 1 |
| ; OPT-NEXT: ret void |
| ; |
| %tmp1 = load i32, ptr %x, align 4 |
| %b = getelementptr inbounds %struct.Y, ptr %y, i64 0, i32 1 |
| %bf.clear = lshr i32 %tmp1, 3 |
| %bf.clear.lobit = and i32 %bf.clear, 1 |
| %frombool = trunc i32 %bf.clear.lobit to i8 |
| store i8 %frombool, ptr %b, align 1 |
| ret void |
| } |
| |
| define i32 @baz(i64 %cav1.coerce) nounwind { |
| ; 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 |
| ret i32 %bf.val.sext |
| } |
| |
| define i32 @bar(i64 %cav1.coerce) nounwind { |
| ; 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 |
| ret i32 %tmp1 |
| } |
| |
| define void @fct1(ptr nocapture %x, ptr nocapture %y) nounwind optsize ssp { |
| ; 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: [[TMP1:%.*]] = load i64, ptr [[X:%.*]], align 4 |
| ; 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]], ptr [[Y:%.*]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| %tmp1 = load i64, ptr %x, align 4 |
| %bf.clear = lshr i64 %tmp1, 3 |
| %bf.clear.lobit = and i64 %bf.clear, 1 |
| store i64 %bf.clear.lobit, ptr %y, align 8 |
| ret void |
| } |
| |
| define i64 @fct2(i64 %cav1.coerce) nounwind { |
| ; 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 { |
| ; 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(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, -16777216 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 16777215 |
| %or = or i64 %and, %and1 |
| store i64 %or, ptr %y, align 8 |
| ret void |
| } |
| |
| define void @fct5(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, -8 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 7 |
| %or = or i32 %and, %and1 |
| store i32 %or, ptr %y, align 8 |
| ret void |
| } |
| |
| ; Check if we can still catch bfm instruction when we drop some low bits |
| define void @fct6(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, -8 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 7 |
| %or = or i32 %and, %and1 |
| %shr1 = lshr i32 %or, 2 |
| store i32 %shr1, ptr %y, align 8 |
| ret void |
| } |
| |
| |
| ; Check if we can still catch bfm instruction when we drop some high bits |
| define void @fct7(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsl is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, -8 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 7 |
| %or = or i32 %and, %and1 |
| %shl = shl i32 %or, 2 |
| store i32 %shl, ptr %y, align 8 |
| ret void |
| } |
| |
| |
| ; Check if we can still catch bfm instruction when we drop some low bits |
| ; (i64 version) |
| define void @fct8(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, -8 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 7 |
| %or = or i64 %and, %and1 |
| %shr1 = lshr i64 %or, 2 |
| store i64 %shr1, ptr %y, align 8 |
| ret void |
| } |
| |
| |
| ; Check if we can still catch bfm instruction when we drop some high bits |
| ; (i64 version) |
| define void @fct9(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, -8 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 7 |
| %or = or i64 %and, %and1 |
| %shl = shl i64 %or, 2 |
| store i64 %shl, ptr %y, align 8 |
| ret void |
| } |
| |
| ; Check if we can catch bfm instruction when lsb is 0 (i.e., no lshr) |
| ; (i32 version) |
| define void @fct10(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsl is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, -8 |
| %and1 = and i32 %x, 7 |
| %or = or i32 %and, %and1 |
| %shl = shl i32 %or, 2 |
| store i32 %shl, ptr %y, align 8 |
| ret void |
| } |
| |
| ; Check if we can catch bfm instruction when lsb is 0 (i.e., no lshr) |
| ; (i64 version) |
| define void @fct11(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsl is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, -8 |
| %and1 = and i64 %x, 7 |
| %or = or i64 %and, %and1 |
| %shl = shl i64 %or, 2 |
| store i64 %shl, ptr %y, align 8 |
| ret void |
| } |
| |
| define zeroext i1 @fct12bis(i32 %tmp2) unnamed_addr nounwind ssp align 2 { |
| ; 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 |
| } |
| |
| ; Check if we can still catch bfm instruction when we drop some high bits |
| ; and some low bits |
| define void @fct12(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, -8 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 7 |
| %or = or i32 %and, %and1 |
| %shl = shl i32 %or, 2 |
| %shr2 = lshr i32 %shl, 4 |
| store i32 %shr2, ptr %y, align 8 |
| ret void |
| } |
| define void @fct12_mask(ptr nocapture %y, i32 %x) nounwind optsize inlinehint ssp { |
| ; LLC-LABEL: fct12_mask: |
| ; LLC: // %bb.0: // %entry |
| ; LLC-NEXT: ldr w8, [x0] |
| ; LLC-NEXT: and w8, w8, #0x3ffffff8 |
| ; LLC-NEXT: bfxil w8, w1, #16, #3 |
| ; LLC-NEXT: lsr w8, w8, #2 |
| ; LLC-NEXT: str w8, [x0] |
| ; LLC-NEXT: ret |
| ; OPT-LABEL: @fct12_mask( |
| ; OPT-NEXT: entry: |
| ; OPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[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: [[LSHR:%.*]] = lshr i32 [[OR]], 2 |
| ; OPT-NEXT: [[MASK:%.*]] = and i32 [[LSHR]], 268435455 |
| ; OPT-NEXT: store i32 [[MASK]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, -8 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 7 |
| %or = or i32 %and, %and1 |
| %lshr = lshr i32 %or, 2 |
| %mask = and i32 %lshr, 268435455 |
| store i32 %mask, ptr %y, align 8 |
| ret void |
| } |
| |
| ; Check if we can still catch bfm instruction when we drop some high bits |
| ; and some low bits |
| ; (i64 version) |
| define void @fct13(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, -8 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 7 |
| %or = or i64 %and, %and1 |
| %shl = shl i64 %or, 2 |
| %shr2 = lshr i64 %shl, 4 |
| store i64 %shr2, ptr %y, align 8 |
| ret void |
| } |
| define void @fct13_mask(ptr nocapture %y, i64 %x) nounwind optsize inlinehint ssp { |
| ; LLC-LABEL: fct13_mask: |
| ; LLC: // %bb.0: // %entry |
| ; LLC-NEXT: ldr x8, [x0] |
| ; LLC-NEXT: and x8, x8, #0x3ffffffffffffff8 |
| ; LLC-NEXT: bfxil x8, x1, #16, #3 |
| ; LLC-NEXT: lsr x8, x8, #2 |
| ; LLC-NEXT: str x8, [x0] |
| ; LLC-NEXT: ret |
| ; OPT-LABEL: @fct13_mask( |
| ; OPT-NEXT: entry: |
| ; OPT-NEXT: [[TMP0:%.*]] = load i64, ptr [[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: [[LSHR:%.*]] = lshr i64 [[OR]], 2 |
| ; OPT-NEXT: [[MASK:%.*]] = and i64 [[LSHR]], 1152921504606846975 |
| ; OPT-NEXT: store i64 [[MASK]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, -8 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 7 |
| %or = or i64 %and, %and1 |
| %lshr = lshr i64 %or, 2 |
| %mask = and i64 %lshr, 1152921504606846975 |
| store i64 %mask, ptr %y, align 8 |
| ret void |
| } |
| |
| |
| ; Check if we can still catch bfm instruction when we drop some high bits |
| ; and some low bits |
| define void @fct14(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| ; lsl is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, -256 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 255 |
| %or = or i32 %and, %and1 |
| %shl = lshr i32 %or, 4 |
| %and2 = and i32 %shl, -8 |
| %shr1 = lshr i32 %x1, 5 |
| %and3 = and i32 %shr1, 7 |
| %or1 = or i32 %and2, %and3 |
| %shl1 = shl i32 %or1, 2 |
| store i32 %shl1, ptr %y, align 8 |
| ret void |
| } |
| |
| ; Check if we can still catch bfm instruction when we drop some high bits |
| ; and some low bits |
| ; (i64 version) |
| define void @fct15(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; lsr is an alias of ubfm |
| ; lsl is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, -256 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 255 |
| %or = or i64 %and, %and1 |
| %shl = lshr i64 %or, 4 |
| %and2 = and i64 %shl, -8 |
| %shr1 = lshr i64 %x1, 5 |
| %and3 = and i64 %shr1, 7 |
| %or1 = or i64 %and2, %and3 |
| %shl1 = shl i64 %or1, 2 |
| store i64 %shl1, ptr %y, align 8 |
| ret void |
| } |
| |
| ; 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(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; Create the constant |
| ; Do the masking |
| ; lsr is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, 1737056 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 7 |
| %or = or i32 %and, %and1 |
| %shl = shl i32 %or, 2 |
| %shr2 = lshr i32 %shl, 4 |
| store i32 %shr2, ptr %y, align 8 |
| ret void |
| } |
| define void @fct16_mask(ptr nocapture %y, i32 %x) nounwind optsize inlinehint ssp { |
| ; LLC-LABEL: fct16_mask: |
| ; 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: lsr w8, w8, #2 |
| ; LLC-NEXT: str w8, [x0] |
| ; LLC-NEXT: ret |
| ; OPT-LABEL: @fct16_mask( |
| ; OPT-NEXT: entry: |
| ; OPT-NEXT: [[TMP0:%.*]] = load i32, ptr [[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: [[LSHR:%.*]] = lshr i32 [[OR]], 2 |
| ; OPT-NEXT: [[MASK:%.*]] = and i32 [[LSHR]], 268435455 |
| ; OPT-NEXT: store i32 [[MASK]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; Create the constant |
| ; Do the masking |
| ; lsr is an alias of ubfm |
| %0 = load i32, ptr %y, align 8 |
| %and = and i32 %0, 1737056 |
| %shr = lshr i32 %x, 16 |
| %and1 = and i32 %shr, 7 |
| %or = or i32 %and, %and1 |
| %lshr = lshr i32 %or, 2 |
| %mask = and i32 %lshr, 268435455 |
| store i32 %mask, ptr %y, align 8 |
| ret void |
| } |
| |
| |
| ; 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 |
| ; (i64 version) |
| define void @fct17(ptr 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, ptr [[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]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; Create the constant |
| ; Do the masking |
| ; lsr is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, 1737056 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 7 |
| %or = or i64 %and, %and1 |
| %shl = shl i64 %or, 2 |
| %shr2 = lshr i64 %shl, 4 |
| store i64 %shr2, ptr %y, align 8 |
| ret void |
| } |
| define void @fct17_mask(ptr nocapture %y, i64 %x) nounwind optsize inlinehint ssp { |
| ; LLC-LABEL: fct17_mask: |
| ; 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: lsr x8, x8, #2 |
| ; LLC-NEXT: str x8, [x0] |
| ; LLC-NEXT: ret |
| ; OPT-LABEL: @fct17_mask( |
| ; OPT-NEXT: entry: |
| ; OPT-NEXT: [[TMP0:%.*]] = load i64, ptr [[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: [[LSHR:%.*]] = lshr i64 [[OR]], 2 |
| ; OPT-NEXT: [[MASK:%.*]] = and i64 [[LSHR]], 1152921504606846975 |
| ; OPT-NEXT: store i64 [[MASK]], ptr [[Y]], align 8 |
| ; OPT-NEXT: ret void |
| ; |
| entry: |
| ; Create the constant |
| ; Do the masking |
| ; lsr is an alias of ubfm |
| %0 = load i64, ptr %y, align 8 |
| %and = and i64 %0, 1737056 |
| %shr = lshr i64 %x, 16 |
| %and1 = and i64 %shr, 7 |
| %or = or i64 %and, %and1 |
| %lshr = lshr i64 %or, 2 |
| %mask = and i64 %lshr, 1152921504606846975 |
| store i64 %mask, ptr %y, align 8 |
| ret void |
| } |
| |
| define i64 @fct18(i32 %xor72) nounwind ssp { |
| ; 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 |
| ret i64 %result |
| } |
| |
| ; Using the access to the global array to keep the instruction and control flow. |
| @first_ones = external dso_local global [65536 x i8] |
| |
| ; Function Attrs: nounwind readonly ssp |
| define i32 @fct19(i64 %arg1) nounwind readonly ssp { |
| ; LLC-LABEL: fct19: |
| ; LLC: // %bb.0: // %entry |
| ; LLC-NEXT: lsr x8, x0, #48 |
| ; LLC-NEXT: cbz x8, .LBB26_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: .LBB26_2: // %if.end |
| ; LLC-NEXT: ubfx x8, x0, #32, #16 |
| ; LLC-NEXT: cbz w8, .LBB26_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 |
| ; LLC-NEXT: ret |
| ; LLC-NEXT: .LBB26_4: // %if.end13 |
| ; LLC-NEXT: lsr w8, w0, #16 |
| ; LLC-NEXT: cbz w8, .LBB26_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 |
| ; LLC-NEXT: ret |
| ; LLC-NEXT: .LBB26_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], ptr @first_ones, i64 0, i64 [[X_SROA_5_0_EXTRACT_SHIFT]] |
| ; OPT-NEXT: [[TMP0:%.*]] = load i8, ptr [[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], ptr @first_ones, i64 0, i64 [[IDXPROM10]] |
| ; OPT-NEXT: [[TMP3:%.*]] = load i8, ptr [[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], ptr @first_ones, i64 0, i64 [[IDXPROM20]] |
| ; OPT-NEXT: [[TMP7:%.*]] = load i8, ptr [[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 |
| %x.sroa.3.0.extract.shift = lshr i64 %arg1, 32 |
| %x.sroa.5.0.extract.shift = lshr i64 %arg1, 48 |
| %tobool = icmp eq i64 %x.sroa.5.0.extract.shift, 0 |
| br i1 %tobool, label %if.end, label %if.then |
| |
| if.then: ; preds = %entry |
| %arrayidx3 = getelementptr inbounds [65536 x i8], ptr @first_ones, i64 0, i64 %x.sroa.5.0.extract.shift |
| %0 = load i8, ptr %arrayidx3, align 1 |
| %conv = zext i8 %0 to i32 |
| br label %return |
| |
| if.end: ; preds = %entry |
| %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 |
| br i1 %tobool6, label %if.end13, label %if.then7 |
| |
| if.then7: ; preds = %if.end |
| ; "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], ptr @first_ones, i64 0, i64 %idxprom10 |
| %1 = load i8, ptr %arrayidx11, align 1 |
| %conv12 = zext i8 %1 to i32 |
| %add = add nsw i32 %conv12, 16 |
| br label %return |
| |
| if.end13: ; preds = %if.end |
| %tobool16 = icmp eq i16 %x.sroa.1.0.extract.trunc, 0 |
| br i1 %tobool16, label %return, label %if.then17 |
| |
| if.then17: ; preds = %if.end13 |
| ; "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], ptr @first_ones, i64 0, i64 %idxprom20 |
| %2 = load i8, ptr %arrayidx21, align 1 |
| %conv22 = zext i8 %2 to i32 |
| %add23 = add nsw i32 %conv22, 32 |
| br label %return |
| |
| return: ; preds = %if.end13, %if.then17, %if.then7, %if.then |
| %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. |
| define i80 @fct20(i128 %a, i128 %b) { |
| ; LLC-LABEL: fct20: |
| ; LLC: // %bb.0: // %entry |
| ; LLC-NEXT: mov x12, #11776 // =0x2e00 |
| ; LLC-NEXT: lsr x8, x1, #18 |
| ; LLC-NEXT: extr x9, x1, x0, #18 |
| ; LLC-NEXT: movk x12, #25856, lsl #16 |
| ; LLC-NEXT: orr x10, x2, x3 |
| ; LLC-NEXT: mov w11, #26220 // =0x666c |
| ; LLC-NEXT: movk x12, #11077, lsl #32 |
| ; LLC-NEXT: and x11, x8, x11 |
| ; LLC-NEXT: cmp x10, #0 |
| ; LLC-NEXT: movk x12, #45, lsl #48 |
| ; LLC-NEXT: csel x1, x11, x8, eq |
| ; LLC-NEXT: and x12, x9, x12 |
| ; LLC-NEXT: csel x0, x12, 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: |
| %and = and i128 %shr, 483673642326615442599424 |
| %conv2 = trunc i128 %and to i80 |
| br label %end |
| end: |
| %conv3 = phi i80 [%conv, %entry], [%conv2, %then] |
| ret i80 %conv3 |
| } |
| |
| ; Check if we can still catch UBFX when "AND" is used by SHL. |
| @arr = external dso_local global [8 x [64 x i64]] |
| define i64 @fct21(i64 %x) { |
| ; LLC-LABEL: fct21: |
| ; LLC: // %bb.0: // %entry |
| ; LLC-NEXT: ubfx x8, x0, #4, #4 |
| ; LLC-NEXT: adrp x9, arr |
| ; 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]], ptr @arr, i64 0, i64 0, i64 [[AND]] |
| ; OPT-NEXT: [[TMP0:%.*]] = load i64, ptr [[ARRAYIDX]], align 8 |
| ; OPT-NEXT: ret i64 [[TMP0]] |
| ; |
| entry: |
| %shr = lshr i64 %x, 4 |
| %and = and i64 %shr, 15 |
| %arrayidx = getelementptr inbounds [8 x [64 x i64]], ptr @arr, i64 0, i64 0, i64 %and |
| %0 = load i64, ptr %arrayidx, align 8 |
| ret i64 %0 |
| } |
| |
| define i16 @test_ignored_rightbits(i32 %dst, i32 %in) { |
| ; LLC-LABEL: test_ignored_rightbits: |
| ; LLC: // %bb.0: |
| ; LLC-NEXT: and w8, w0, #0x7 |
| ; LLC-NEXT: bfi w8, w1, #3, #4 |
| ; LLC-NEXT: orr w0, w8, w8, lsl #8 |
| ; 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 |
| |
| %shl16 = shl i32 %insertion, 8 |
| %or18 = or i32 %shl16, %insertion |
| %conv19 = trunc i32 %or18 to i16 |
| |
| ret i16 %conv19 |
| } |
| |
| ; 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. |
| define void @sameOperandBFI(i64 %src, i64 %src2, ptr %ptr) { |
| ; LLC-LABEL: sameOperandBFI: |
| ; LLC: // %bb.0: // %entry |
| ; LLC-NEXT: cbnz wzr, .LBB30_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: orr w8, w9, w9, lsl #4 |
| ; LLC-NEXT: strh w8, [x2] |
| ; LLC-NEXT: .LBB30_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]], ptr [[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 |
| br i1 undef, label %end, label %if.else |
| |
| if.else: |
| %and3 = and i32 %src2.trunc, 3 |
| %shl2 = shl nuw nsw i64 %shr47, 2 |
| %shl2.trunc = trunc i64 %shl2 to i32 |
| %and12 = and i32 %shl2.trunc, 12 |
| %BFISource = or i32 %and3, %and12 ; ...00000ABCD |
| %BFIRHS = shl nuw nsw i32 %BFISource, 4 ; ...0ABCD0000 |
| %BFI = or i32 %BFIRHS, %BFISource ; ...0ABCDABCD |
| %BFItrunc = trunc i32 %BFI to i16 |
| store i16 %BFItrunc, ptr %ptr, align 4 |
| br label %end |
| |
| end: |
| ret void |
| } |