Index: llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp +++ llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp @@ -31,6 +31,8 @@ // If AArch64's 32-bit form of instruction defines the source operand of // ORRWrs, we can remove the ORRWrs because the upper 32 bits of the source // operand are set to zero. +// 5. lsr x1, x0, n0 +// lsr x2, x1, n1 ==> lsr x2, x0, (n0 + n1) // //===----------------------------------------------------------------------===// @@ -102,6 +104,8 @@ SmallSetVector &ToBeRemoved); bool visitORR(MachineInstr &MI, SmallSetVector &ToBeRemoved); + bool visitUBFM(MachineInstr &MI, + SmallSetVector &ToBeRemoved); bool runOnMachineFunction(MachineFunction &MF) override; StringRef getPassName() const override { @@ -464,6 +468,43 @@ return true; } +bool AArch64MIPeepholeOpt::visitUBFM( + MachineInstr &MI, SmallSetVector &ToBeRemoved) { + // lsr x1, x0, n0 + // lsr x2, x1, n1 ==> lsr x2, x0, (n0 + n1) + // condition: x1 has only one use + unsigned RegSize = MI.getOpcode() == AArch64::UBFMWri ? 32 : 64; + if (!MI.getOperand(2).isImm() || !MI.getOperand(3).isImm()) + return false; + + if (MI.getOperand(3).getImm() != RegSize - 1) + return false; + + Register MISrc1Reg = MI.getOperand(1).getReg(); + if (!MRI->hasOneUse(MISrc1Reg)) + return false; + + MachineInstr &MI2 = *MRI->getUniqueVRegDef(MISrc1Reg); + if (MI2.getOpcode() != MI.getOpcode()) + return false; + + if (!MI2.getOperand(2).isImm() || !MI2.getOperand(3).isImm()) + return false; + + if (MI2.getOperand(3).getImm() != RegSize - 1) + return false; + + int64_t Imm = MI.getOperand(2).getImm() + MI2.getOperand(2).getImm(); + if (Imm >= RegSize) + return false; + + MI.getOperand(1).setReg(MI2.getOperand(1).getReg()); + MI.getOperand(2).setImm(Imm); + ToBeRemoved.insert(&MI2); + + return true; +} + bool AArch64MIPeepholeOpt::runOnMachineFunction(MachineFunction &MF) { if (skipFunction(MF.getFunction())) return false; @@ -529,6 +570,10 @@ {AArch64::ADDXri, AArch64::ADDSXri}, MI, ToBeRemoved); break; + case AArch64::UBFMWri: + case AArch64::UBFMXri: + Changed = visitUBFM(MI, ToBeRemoved); + break; } } } Index: llvm/test/CodeGen/AArch64/aarch64-ubfm.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/aarch64-ubfm.ll @@ -0,0 +1,41 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64-none-linux-gnu < %s -o -| FileCheck %s + +define i32 @copy_hex_nibble_from_4_to_1(i32 %a) { +; CHECK-LABEL: copy_hex_nibble_from_4_to_1: +; CHECK: // %bb.0: +; CHECK-NEXT: lsr w8, w0, #20 +; CHECK-NEXT: bfi w0, w8, #4, #4 +; CHECK-NEXT: ret + %and1 = and i32 %a, -241 + %1 = lshr i32 %a, 16 + %shl = and i32 %1, 240 + %or = or i32 %shl, %and1 + ret i32 %or +} + +define i32 @copy_hex_nibble_from_3_to_1(i32 %a) { +; CHECK-LABEL: copy_hex_nibble_from_3_to_1: +; CHECK: // %bb.0: +; CHECK-NEXT: lsr w8, w0, #16 +; CHECK-NEXT: bfi w0, w8, #4, #4 +; CHECK-NEXT: ret + %and1 = and i32 %a, -241 + %1 = lshr i32 %a, 12 + %shl = and i32 %1, 240 + %or = or i32 %shl, %and1 + ret i32 %or +} + +define i32 @copy_5_bits_to_offset_1(i32 %a) { +; CHECK-LABEL: copy_5_bits_to_offset_1: +; CHECK: // %bb.0: +; CHECK-NEXT: lsr w8, w0, #20 +; CHECK-NEXT: bfi w0, w8, #1, #5 +; CHECK-NEXT: ret + %and1 = and i32 %a, -63 + %1 = lshr i32 %a, 19 + %shl = and i32 %1, 62 + %or = or i32 %shl, %and1 + ret i32 %or +}