Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AArch64] merge index address with large offset into base address #72187

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "AArch64ExpandImm.h"
#include "AArch64MachineFunctionInfo.h"
#include "AArch64TargetMachine.h"
#include "MCTargetDesc/AArch64AddressingModes.h"
Expand Down Expand Up @@ -1074,6 +1075,41 @@ bool AArch64DAGToDAGISel::SelectAddrModeIndexedBitWidth(SDValue N, bool IsSigned
return true;
}

// 16-bit optionally shifted immediates are legal for single mov.
static bool isLegalSingleMOVImmediate(int64_t Immed) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this make use of expandMOVImm?

    AArch64_IMM::expandMOVImm(UImm, BitSize, Insn);
    if (Insn.size() != 1)
      return;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apply your comment, thanks

if (Immed == std::numeric_limits<int64_t>::min()) {
LLVM_DEBUG(dbgs() << "Illegal single mov imm " << Immed
<< ": avoid UB for INT64_MIN\n");
return false;
}

// Calculate how many moves we will need to materialize this constant.
SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
AArch64_IMM::expandMOVImm(Immed, 64, Insn);
return Insn.size() == 1;
}

// Check whether a unsigned vaule is not in the immediate range of mov but in
// the immediate range of imm24. The "Size" argument is the size in bytes of the
// memory reference.
static bool isPreferredBaseAddrMode(const TargetLowering *TLI, int64_t ImmOff,
unsigned Size) {
if ((ImmOff & (Size - 1)) != 0 || ImmOff < 0)
return false;

// If the immediate already can be encoded in mov, then just keep the existing
// logic.
if (isLegalSingleMOVImmediate(ImmOff))
return false;

// For a imm24, its low imm12 can be fold as the immediate of load or store,
// and its high part can be encoded in an add.
int64_t HighPart = ImmOff & ~0xfffULL;
if (TLI->isLegalAddImmediate(HighPart))
return true;
return false;
}

/// SelectAddrModeIndexed - Select a "register plus scaled unsigned 12-bit
/// immediate" address. The "Size" argument is the size in bytes of the memory
/// reference, which determines the scale.
Expand Down Expand Up @@ -1115,6 +1151,24 @@ bool AArch64DAGToDAGISel::SelectAddrModeIndexed(SDValue N, unsigned Size,
OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64);
return true;
}

// Perfer [Reg + imm] mode.
// ADD BaseReg, WideImmediate & 0x0fff000
// LDR X2, [BaseReg, WideImmediate & 0x0fff]
SDValue LHS = N.getOperand(0);
if (isPreferredBaseAddrMode(TLI, RHSC, Size)) {
int64_t ImmOffUnScale = RHSC;
int64_t ImmOffLow = ImmOffUnScale & 0x0fff;
int64_t ImmOffHigh = RHSC - ImmOffLow;
SDValue ImmHighSDV =
CurDAG->getTargetConstant(ImmOffHigh >> 12, dl, MVT::i64);
Base = SDValue(CurDAG->getMachineNode(
AArch64::ADDXri, dl, MVT::i64, LHS, ImmHighSDV,
CurDAG->getTargetConstant(12, dl, MVT::i32)),
0);
OffImm = CurDAG->getTargetConstant(ImmOffLow >> Scale, dl, MVT::i64);
return true;
}
}
}

Expand Down Expand Up @@ -1356,6 +1410,14 @@ bool AArch64DAGToDAGISel::SelectAddrModeXRO(SDValue N, unsigned Size,
return true;
}

// Perfer [Reg + imm] mode, so skip this scenarios.
if (auto *OffsetC = dyn_cast<ConstantSDNode>(RHS)) {
int64_t ImmOff = (int64_t)OffsetC->getZExtValue();
const TargetLowering *TLI = getTargetLowering();
if (isPreferredBaseAddrMode(TLI, ImmOff, Size)) {
return false;
}
}
// Match any non-shifted, non-extend, non-immediate add expression.
Base = LHS;
Offset = RHS;
Expand Down
15 changes: 6 additions & 9 deletions llvm/test/CodeGen/AArch64/arm64-addrmode.ll
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,8 @@ define void @t17(i64 %a) {
define i32 @LdOffset_i8(ptr %a) {
; CHECK-LABEL: LdOffset_i8:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #56952 // =0xde78
; CHECK-NEXT: movk w8, #15, lsl #16
; CHECK-NEXT: ldrb w0, [x0, x8]
; CHECK-NEXT: add x8, x0, #253, lsl #12 // =1036288
; CHECK-NEXT: ldrb w0, [x8, #3704]
; CHECK-NEXT: ret
%arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
%val = load i8, ptr %arrayidx, align 1
Expand All @@ -226,9 +225,8 @@ define i32 @LdOffset_i8(ptr %a) {
define i32 @LdOffset_i16(ptr %a) {
; CHECK-LABEL: LdOffset_i16:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #48368 // =0xbcf0
; CHECK-NEXT: movk w8, #31, lsl #16
; CHECK-NEXT: ldrsh w0, [x0, x8]
; CHECK-NEXT: add x8, x0, #507, lsl #12 // =2076672
; CHECK-NEXT: ldrsh w0, [x8, #3312]
; CHECK-NEXT: ret
%arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
vfdff marked this conversation as resolved.
Show resolved Hide resolved
%val = load i16, ptr %arrayidx, align 2
Expand All @@ -239,9 +237,8 @@ define i32 @LdOffset_i16(ptr %a) {
define i32 @LdOffset_i32(ptr %a) {
; CHECK-LABEL: LdOffset_i32:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #31200 // =0x79e0
; CHECK-NEXT: movk w8, #63, lsl #16
; CHECK-NEXT: ldr w0, [x0, x8]
; CHECK-NEXT: add x8, x0, #1015, lsl #12 // =4157440
; CHECK-NEXT: ldr w0, [x8, #2528]
; CHECK-NEXT: ret
%arrayidx = getelementptr inbounds i32, ptr %a, i64 1039992
%val = load i32, ptr %arrayidx, align 4
Expand Down