Skip to content

Commit 7a0024d

Browse files
authored
[AArch64] Refactor AND/ANDS bitmask splitting (NFC). (#150619)
This patch generalises the logic for splitting bitmasks for AND/ANDS immediate instructions, to prepare it to handle more opcodes, as in #150394.
1 parent c4b1557 commit 7a0024d

File tree

1 file changed

+38
-19
lines changed

1 file changed

+38
-19
lines changed

llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// MOVi64imm + ANDS?Xrr ==> ANDXri + ANDS?Xri
1313
//
1414
// 2. MOVi32imm + ADDWrr ==> ADDWRi + ADDWRi
15-
// MOVi64imm + ADDXrr ==> ANDXri + ANDXri
15+
// MOVi64imm + ADDXrr ==> ADDXri + ADDXri
1616
//
1717
// 3. MOVi32imm + SUBWrr ==> SUBWRi + SUBWRi
1818
// MOVi64imm + SUBXrr ==> SUBXri + SUBXri
@@ -125,8 +125,13 @@ struct AArch64MIPeepholeOpt : public MachineFunctionPass {
125125
template <typename T>
126126
bool visitADDSSUBS(OpcodePair PosOpcs, OpcodePair NegOpcs, MachineInstr &MI);
127127

128+
// Strategy used to split logical immediate bitmasks.
129+
enum class SplitStrategy {
130+
Intersect,
131+
};
128132
template <typename T>
129-
bool visitAND(unsigned Opc, MachineInstr &MI, unsigned OtherOpc = 0);
133+
bool trySplitLogicalImm(unsigned Opc, MachineInstr &MI,
134+
SplitStrategy Strategy, unsigned OtherOpc = 0);
130135
bool visitORR(MachineInstr &MI);
131136
bool visitCSEL(MachineInstr &MI);
132137
bool visitINSERT(MachineInstr &MI);
@@ -158,14 +163,6 @@ INITIALIZE_PASS(AArch64MIPeepholeOpt, "aarch64-mi-peephole-opt",
158163
template <typename T>
159164
static bool splitBitmaskImm(T Imm, unsigned RegSize, T &Imm1Enc, T &Imm2Enc) {
160165
T UImm = static_cast<T>(Imm);
161-
if (AArch64_AM::isLogicalImmediate(UImm, RegSize))
162-
return false;
163-
164-
// If this immediate can be handled by one instruction, do not split it.
165-
SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
166-
AArch64_IMM::expandMOVImm(UImm, RegSize, Insn);
167-
if (Insn.size() == 1)
168-
return false;
169166

170167
// The bitmask immediate consists of consecutive ones. Let's say there is
171168
// constant 0b00000000001000000000010000000000 which does not consist of
@@ -194,8 +191,9 @@ static bool splitBitmaskImm(T Imm, unsigned RegSize, T &Imm1Enc, T &Imm2Enc) {
194191
}
195192

196193
template <typename T>
197-
bool AArch64MIPeepholeOpt::visitAND(unsigned Opc, MachineInstr &MI,
198-
unsigned OtherOpc) {
194+
bool AArch64MIPeepholeOpt::trySplitLogicalImm(unsigned Opc, MachineInstr &MI,
195+
SplitStrategy Strategy,
196+
unsigned OtherOpc) {
199197
// Try below transformation.
200198
//
201199
// MOVi32imm + ANDS?Wrr ==> ANDWri + ANDS?Wri
@@ -208,9 +206,26 @@ bool AArch64MIPeepholeOpt::visitAND(unsigned Opc, MachineInstr &MI,
208206

209207
return splitTwoPartImm<T>(
210208
MI,
211-
[Opc, OtherOpc](T Imm, unsigned RegSize, T &Imm0,
212-
T &Imm1) -> std::optional<OpcodePair> {
213-
if (splitBitmaskImm(Imm, RegSize, Imm0, Imm1))
209+
[Opc, Strategy, OtherOpc](T Imm, unsigned RegSize, T &Imm0,
210+
T &Imm1) -> std::optional<OpcodePair> {
211+
// If this immediate is already a suitable bitmask, don't split it.
212+
// TODO: Should we just combine the two instructions in this case?
213+
if (AArch64_AM::isLogicalImmediate(Imm, RegSize))
214+
return std::nullopt;
215+
216+
// If this immediate can be handled by one instruction, don't split it.
217+
SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
218+
AArch64_IMM::expandMOVImm(Imm, RegSize, Insn);
219+
if (Insn.size() == 1)
220+
return std::nullopt;
221+
222+
bool SplitSucc = false;
223+
switch (Strategy) {
224+
case SplitStrategy::Intersect:
225+
SplitSucc = splitBitmaskImm(Imm, RegSize, Imm0, Imm1);
226+
break;
227+
}
228+
if (SplitSucc)
214229
return std::make_pair(Opc, !OtherOpc ? Opc : OtherOpc);
215230
return std::nullopt;
216231
},
@@ -859,16 +874,20 @@ bool AArch64MIPeepholeOpt::runOnMachineFunction(MachineFunction &MF) {
859874
Changed |= visitINSERT(MI);
860875
break;
861876
case AArch64::ANDWrr:
862-
Changed |= visitAND<uint32_t>(AArch64::ANDWri, MI);
877+
Changed |= trySplitLogicalImm<uint32_t>(AArch64::ANDWri, MI,
878+
SplitStrategy::Intersect);
863879
break;
864880
case AArch64::ANDXrr:
865-
Changed |= visitAND<uint64_t>(AArch64::ANDXri, MI);
881+
Changed |= trySplitLogicalImm<uint64_t>(AArch64::ANDXri, MI,
882+
SplitStrategy::Intersect);
866883
break;
867884
case AArch64::ANDSWrr:
868-
Changed |= visitAND<uint32_t>(AArch64::ANDWri, MI, AArch64::ANDSWri);
885+
Changed |= trySplitLogicalImm<uint32_t>(
886+
AArch64::ANDWri, MI, SplitStrategy::Intersect, AArch64::ANDSWri);
869887
break;
870888
case AArch64::ANDSXrr:
871-
Changed |= visitAND<uint64_t>(AArch64::ANDXri, MI, AArch64::ANDSXri);
889+
Changed |= trySplitLogicalImm<uint64_t>(
890+
AArch64::ANDXri, MI, SplitStrategy::Intersect, AArch64::ANDSXri);
872891
break;
873892
case AArch64::ORRWrs:
874893
Changed |= visitORR(MI);

0 commit comments

Comments
 (0)