Skip to content

Commit e5296d3

Browse files
committed
[AArch64] merge index address with large offset into base address
A case for this transformation, https://gcc.godbolt.org/z/nhYcWq1WE ``` Fold mov w8, llvm#56952 movk w8, llvm#15, lsl llvm#16 ldrb w0, [x0, x8] into add x0, x0, 1036288 ldrb w0, [x0, 3704] ``` Only support single use base, multi-use scenes are supported by PR74046. Fix llvm#71917 TODO: support the multiple-uses with reuseing common base offset. https://gcc.godbolt.org/z/Mr7srTjnz
1 parent 2fd66e6 commit e5296d3

File tree

2 files changed

+68
-9
lines changed

2 files changed

+68
-9
lines changed

llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "AArch64ExpandImm.h"
1314
#include "AArch64MachineFunctionInfo.h"
1415
#include "AArch64TargetMachine.h"
1516
#include "MCTargetDesc/AArch64AddressingModes.h"
@@ -1074,6 +1075,41 @@ bool AArch64DAGToDAGISel::SelectAddrModeIndexedBitWidth(SDValue N, bool IsSigned
10741075
return true;
10751076
}
10761077

1078+
// 16-bit optionally shifted immediates are legal for single mov.
1079+
static bool isLegalSingleMOVImmediate(int64_t Immed) {
1080+
if (Immed == std::numeric_limits<int64_t>::min()) {
1081+
LLVM_DEBUG(dbgs() << "Illegal single mov imm " << Immed
1082+
<< ": avoid UB for INT64_MIN\n");
1083+
return false;
1084+
}
1085+
1086+
// Calculate how many moves we will need to materialize this constant.
1087+
SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
1088+
AArch64_IMM::expandMOVImm(Immed, 64, Insn);
1089+
return Insn.size() == 1;
1090+
}
1091+
1092+
// Check whether a unsigned vaule is not in the immediate range of mov but in
1093+
// the immediate range of imm24. The "Size" argument is the size in bytes of the
1094+
// memory reference.
1095+
static bool isPreferredBaseAddrMode(const TargetLowering *TLI, int64_t ImmOff,
1096+
unsigned Size) {
1097+
if ((ImmOff & (Size - 1)) != 0 || ImmOff < 0)
1098+
return false;
1099+
1100+
// If the immediate already can be encoded in mov, then just keep the existing
1101+
// logic.
1102+
if (isLegalSingleMOVImmediate(ImmOff))
1103+
return false;
1104+
1105+
// For a imm24, its low imm12 can be fold as the immediate of load or store,
1106+
// and its high part can be encoded in an add.
1107+
int64_t HighPart = ImmOff & ~0xfffULL;
1108+
if (TLI->isLegalAddImmediate(HighPart))
1109+
return true;
1110+
return false;
1111+
}
1112+
10771113
/// SelectAddrModeIndexed - Select a "register plus scaled unsigned 12-bit
10781114
/// immediate" address. The "Size" argument is the size in bytes of the memory
10791115
/// reference, which determines the scale.
@@ -1115,6 +1151,24 @@ bool AArch64DAGToDAGISel::SelectAddrModeIndexed(SDValue N, unsigned Size,
11151151
OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64);
11161152
return true;
11171153
}
1154+
1155+
// Perfer [Reg + imm] mode.
1156+
// ADD BaseReg, WideImmediate & 0x0fff000
1157+
// LDR X2, [BaseReg, WideImmediate & 0x0fff]
1158+
SDValue LHS = N.getOperand(0);
1159+
if (isPreferredBaseAddrMode(TLI, RHSC, Size)) {
1160+
int64_t ImmOffUnScale = RHSC;
1161+
int64_t ImmOffLow = ImmOffUnScale & 0x0fff;
1162+
int64_t ImmOffHigh = RHSC - ImmOffLow;
1163+
SDValue ImmHighSDV =
1164+
CurDAG->getTargetConstant(ImmOffHigh >> 12, dl, MVT::i64);
1165+
Base = SDValue(CurDAG->getMachineNode(
1166+
AArch64::ADDXri, dl, MVT::i64, LHS, ImmHighSDV,
1167+
CurDAG->getTargetConstant(12, dl, MVT::i32)),
1168+
0);
1169+
OffImm = CurDAG->getTargetConstant(ImmOffLow >> Scale, dl, MVT::i64);
1170+
return true;
1171+
}
11181172
}
11191173
}
11201174

@@ -1356,6 +1410,14 @@ bool AArch64DAGToDAGISel::SelectAddrModeXRO(SDValue N, unsigned Size,
13561410
return true;
13571411
}
13581412

1413+
// Perfer [Reg + imm] mode, so skip this scenarios.
1414+
if (auto *OffsetC = dyn_cast<ConstantSDNode>(RHS)) {
1415+
int64_t ImmOff = (int64_t)OffsetC->getZExtValue();
1416+
const TargetLowering *TLI = getTargetLowering();
1417+
if (isPreferredBaseAddrMode(TLI, ImmOff, Size)) {
1418+
return false;
1419+
}
1420+
}
13591421
// Match any non-shifted, non-extend, non-immediate add expression.
13601422
Base = LHS;
13611423
Offset = RHS;

llvm/test/CodeGen/AArch64/arm64-addrmode.ll

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,8 @@ define void @t17(i64 %a) {
213213
define i32 @LdOffset_i8(ptr %a) {
214214
; CHECK-LABEL: LdOffset_i8:
215215
; CHECK: // %bb.0:
216-
; CHECK-NEXT: mov w8, #56952 // =0xde78
217-
; CHECK-NEXT: movk w8, #15, lsl #16
218-
; CHECK-NEXT: ldrb w0, [x0, x8]
216+
; CHECK-NEXT: add x8, x0, #253, lsl #12 // =1036288
217+
; CHECK-NEXT: ldrb w0, [x8, #3704]
219218
; CHECK-NEXT: ret
220219
%arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
221220
%val = load i8, ptr %arrayidx, align 1
@@ -226,9 +225,8 @@ define i32 @LdOffset_i8(ptr %a) {
226225
define i32 @LdOffset_i16(ptr %a) {
227226
; CHECK-LABEL: LdOffset_i16:
228227
; CHECK: // %bb.0:
229-
; CHECK-NEXT: mov w8, #48368 // =0xbcf0
230-
; CHECK-NEXT: movk w8, #31, lsl #16
231-
; CHECK-NEXT: ldrsh w0, [x0, x8]
228+
; CHECK-NEXT: add x8, x0, #507, lsl #12 // =2076672
229+
; CHECK-NEXT: ldrsh w0, [x8, #3312]
232230
; CHECK-NEXT: ret
233231
%arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
234232
%val = load i16, ptr %arrayidx, align 2
@@ -239,9 +237,8 @@ define i32 @LdOffset_i16(ptr %a) {
239237
define i32 @LdOffset_i32(ptr %a) {
240238
; CHECK-LABEL: LdOffset_i32:
241239
; CHECK: // %bb.0:
242-
; CHECK-NEXT: mov w8, #31200 // =0x79e0
243-
; CHECK-NEXT: movk w8, #63, lsl #16
244-
; CHECK-NEXT: ldr w0, [x0, x8]
240+
; CHECK-NEXT: add x8, x0, #1015, lsl #12 // =4157440
241+
; CHECK-NEXT: ldr w0, [x8, #2528]
245242
; CHECK-NEXT: ret
246243
%arrayidx = getelementptr inbounds i32, ptr %a, i64 1039992
247244
%val = load i32, ptr %arrayidx, align 4

0 commit comments

Comments
 (0)