return false;
}
case Instruction::Add: {
- // Check to see if we can merge in the RHS then the LHS. If so, we win.
+ // Check to see if we can merge in one operand, then the other. If so, we
+ // win.
ExtAddrMode BackupAddrMode = AddrMode;
unsigned OldSize = AddrModeInsts.size();
// Start a transaction at this point.
TypePromotionTransaction::ConstRestorationPt LastKnownGood =
TPT.getRestorationPoint();
+ // Try to match an integer constant second to increase its chance of ending
+ // up in `BaseOffs`, resp. decrease its chance of ending up in `BaseReg`.
+ int First = 0, Second = 1;
+ if (isa<ConstantInt>(AddrInst->getOperand(First))
+ && !isa<ConstantInt>(AddrInst->getOperand(Second)))
+ std::swap(First, Second);
AddrMode.InBounds = false;
- if (matchAddr(AddrInst->getOperand(1), Depth + 1) &&
- matchAddr(AddrInst->getOperand(0), Depth + 1))
+ if (matchAddr(AddrInst->getOperand(First), Depth + 1) &&
+ matchAddr(AddrInst->getOperand(Second), Depth + 1))
return true;
// Restore the old addr mode info.
AddrModeInsts.resize(OldSize);
TPT.rollback(LastKnownGood);
- // Otherwise this was over-aggressive. Try merging in the LHS then the RHS.
- if (matchAddr(AddrInst->getOperand(0), Depth + 1) &&
- matchAddr(AddrInst->getOperand(1), Depth + 1))
+ // Otherwise this was over-aggressive. Try merging operands in the opposite
+ // order.
+ if (matchAddr(AddrInst->getOperand(Second), Depth + 1) &&
+ matchAddr(AddrInst->getOperand(First), Depth + 1))
return true;
// Otherwise we definitely can't merge the ADD in.
// just add it to the disp field and check validity.
if (VariableOperand == -1) {
AddrMode.BaseOffs += ConstantOffset;
- if (ConstantOffset == 0 ||
- TLI.isLegalAddressingMode(DL, AddrMode, AccessTy, AddrSpace)) {
- // Check to see if we can fold the base pointer in too.
- if (matchAddr(AddrInst->getOperand(0), Depth + 1)) {
+ if (matchAddr(AddrInst->getOperand(0), Depth + 1)) {
if (!cast<GEPOperator>(AddrInst)->isInBounds())
AddrMode.InBounds = false;
return true;
- }
- } else if (EnableGEPOffsetSplit && isa<GetElementPtrInst>(AddrInst) &&
- TLI.shouldConsiderGEPOffsetSplit() && Depth == 0 &&
- ConstantOffset > 0) {
- // Record GEPs with non-zero offsets as candidates for splitting in the
- // event that the offset cannot fit into the r+i addressing mode.
- // Simple and common case that only one GEP is used in calculating the
- // address for the memory access.
- Value *Base = AddrInst->getOperand(0);
- auto *BaseI = dyn_cast<Instruction>(Base);
- auto *GEP = cast<GetElementPtrInst>(AddrInst);
- if (isa<Argument>(Base) || isa<GlobalValue>(Base) ||
- (BaseI && !isa<CastInst>(BaseI) &&
- !isa<GetElementPtrInst>(BaseI))) {
- // Make sure the parent block allows inserting non-PHI instructions
- // before the terminator.
- BasicBlock *Parent =
- BaseI ? BaseI->getParent() : &GEP->getFunction()->getEntryBlock();
- if (!Parent->getTerminator()->isEHPad())
- LargeOffsetGEP = std::make_pair(GEP, ConstantOffset);
- }
}
AddrMode.BaseOffs -= ConstantOffset;
+
+ if (EnableGEPOffsetSplit && isa<GetElementPtrInst>(AddrInst) &&
+ TLI.shouldConsiderGEPOffsetSplit() && Depth == 0 &&
+ ConstantOffset > 0) {
+ // Record GEPs with non-zero offsets as candidates for splitting in
+ // the event that the offset cannot fit into the r+i addressing mode.
+ // Simple and common case that only one GEP is used in calculating the
+ // address for the memory access.
+ Value *Base = AddrInst->getOperand(0);
+ auto *BaseI = dyn_cast<Instruction>(Base);
+ auto *GEP = cast<GetElementPtrInst>(AddrInst);
+ if (isa<Argument>(Base) || isa<GlobalValue>(Base) ||
+ (BaseI && !isa<CastInst>(BaseI) &&
+ !isa<GetElementPtrInst>(BaseI))) {
+ // Make sure the parent block allows inserting non-PHI instructions
+ // before the terminator.
+ BasicBlock *Parent = BaseI ? BaseI->getParent()
+ : &GEP->getFunction()->getEntryBlock();
+ if (!Parent->getTerminator()->isEHPad())
+ LargeOffsetGEP = std::make_pair(GEP, ConstantOffset);
+ }
+ }
+
return false;
}
int64_t Offset = LargeOffsetGEP->second;
if (Offset != BaseOffset) {
TargetLowering::AddrMode AddrMode;
+ AddrMode.HasBaseReg = true;
AddrMode.BaseOffs = Offset - BaseOffset;
// The result type of the GEP might not be the type of the memory
// access.
--- /dev/null
+#include "AArch64Subtarget.h"
+#include "AArch64TargetMachine.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "gtest/gtest.h"
+#include <initializer_list>
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+struct TestCase {
+ TargetLowering::AddrMode AM;
+ unsigned TypeBits;
+ bool Result;
+};
+
+const std::initializer_list<TestCase> Tests = {
+ // {BaseGV, BaseOffs, HasBaseReg, Scale}, Bits, Result
+ {{reinterpret_cast<GlobalValue *>(-1), 0, false}, 64, false},
+ {{nullptr, 8, true, 1}, 64, false},
+ {{nullptr, 0, false, 2}, 64, true},
+ {{nullptr, 0, false, 1}, 64, true},
+ {{nullptr, 4, false, 0}, 64, false},
+
+ {{nullptr, 0, true, 1}, 64, true},
+ {{nullptr, 0, true, 1}, 32, true},
+ {{nullptr, 0, true, 1}, 16, true},
+ {{nullptr, 0, true, 1}, 8, true},
+
+ {{nullptr, 0, true, 2}, 64, false},
+ {{nullptr, 0, true, 2}, 32, false},
+ {{nullptr, 0, true, 2}, 16, true},
+ {{nullptr, 0, true, 2}, 8, false},
+ {{nullptr, 0, true, 4}, 64, false},
+ {{nullptr, 0, true, 4}, 32, true},
+ {{nullptr, 0, true, 4}, 16, false},
+ {{nullptr, 0, true, 4}, 8, false},
+
+ {{nullptr, 0, true, 8}, 64, true},
+ {{nullptr, 0, true, 8}, 32, false},
+ {{nullptr, 0, true, 8}, 16, false},
+ {{nullptr, 0, true, 8}, 8, false},
+
+ {{nullptr, 0, true, 16}, 64, false},
+ {{nullptr, 0, true, 16}, 32, false},
+ {{nullptr, 0, true, 16}, 16, false},
+ {{nullptr, 0, true, 16}, 8, false},
+
+ {{nullptr, -257, true, 0}, 64, false},
+ {{nullptr, -256, true, 0}, 64, true},
+ {{nullptr, -255, true, 0}, 64, true},
+ {{nullptr, -1, true, 0}, 64, true},
+ {{nullptr, 0, true, 0}, 64, true},
+ {{nullptr, 1, true, 0}, 64, true},
+ {{nullptr, 254, true, 0}, 64, true},
+ {{nullptr, 255, true, 0}, 64, true},
+ {{nullptr, 256, true, 0}, 64, true},
+ {{nullptr, 257, true, 0}, 64, false},
+ {{nullptr, 258, true, 0}, 64, false},
+ {{nullptr, 259, true, 0}, 64, false},
+ {{nullptr, 260, true, 0}, 64, false},
+ {{nullptr, 261, true, 0}, 64, false},
+ {{nullptr, 262, true, 0}, 64, false},
+ {{nullptr, 263, true, 0}, 64, false},
+ {{nullptr, 264, true, 0}, 64, true},
+
+ {{nullptr, 4096 * 8 - 8, true, 0}, 64, true},
+ {{nullptr, 4096 * 8 - 7, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 - 6, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 - 5, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 - 4, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 - 3, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 - 2, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 - 1, true, 0}, 64, false},
+ {{nullptr, 4096 * 8, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 1, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 2, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 3, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 4, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 5, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 6, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 7, true, 0}, 64, false},
+ {{nullptr, 4096 * 8 + 8, true, 0}, 64, false},
+
+ {{nullptr, -257, true, 0}, 32, false},
+ {{nullptr, -256, true, 0}, 32, true},
+ {{nullptr, -255, true, 0}, 32, true},
+ {{nullptr, -1, true, 0}, 32, true},
+ {{nullptr, 0, true, 0}, 32, true},
+ {{nullptr, 1, true, 0}, 32, true},
+ {{nullptr, 254, true, 0}, 32, true},
+ {{nullptr, 255, true, 0}, 32, true},
+ {{nullptr, 256, true, 0}, 32, true},
+ {{nullptr, 257, true, 0}, 32, false},
+ {{nullptr, 258, true, 0}, 32, false},
+ {{nullptr, 259, true, 0}, 32, false},
+ {{nullptr, 260, true, 0}, 32, true},
+
+ {{nullptr, 4096 * 4 - 4, true, 0}, 32, true},
+ {{nullptr, 4096 * 4 - 3, true, 0}, 32, false},
+ {{nullptr, 4096 * 4 - 2, true, 0}, 32, false},
+ {{nullptr, 4096 * 4 - 1, true, 0}, 32, false},
+ {{nullptr, 4096 * 4, true, 0}, 32, false},
+ {{nullptr, 4096 * 4 + 1, true, 0}, 32, false},
+ {{nullptr, 4096 * 4 + 2, true, 0}, 32, false},
+ {{nullptr, 4096 * 4 + 3, true, 0}, 32, false},
+ {{nullptr, 4096 * 4 + 4, true, 0}, 32, false},
+
+ {{nullptr, -257, true, 0}, 16, false},
+ {{nullptr, -256, true, 0}, 16, true},
+ {{nullptr, -255, true, 0}, 16, true},
+ {{nullptr, -1, true, 0}, 16, true},
+ {{nullptr, 0, true, 0}, 16, true},
+ {{nullptr, 1, true, 0}, 16, true},
+ {{nullptr, 254, true, 0}, 16, true},
+ {{nullptr, 255, true, 0}, 16, true},
+ {{nullptr, 256, true, 0}, 16, true},
+ {{nullptr, 257, true, 0}, 16, false},
+ {{nullptr, 258, true, 0}, 16, true},
+
+ {{nullptr, 4096 * 2 - 2, true, 0}, 16, true},
+ {{nullptr, 4096 * 2 - 1, true, 0}, 16, false},
+ {{nullptr, 4096 * 2, true, 0}, 16, false},
+ {{nullptr, 4096 * 2 + 1, true, 0}, 16, false},
+ {{nullptr, 4096 * 2 + 2, true, 0}, 16, false},
+
+ {{nullptr, -257, true, 0}, 8, false},
+ {{nullptr, -256, true, 0}, 8, true},
+ {{nullptr, -255, true, 0}, 8, true},
+ {{nullptr, -1, true, 0}, 8, true},
+ {{nullptr, 0, true, 0}, 8, true},
+ {{nullptr, 1, true, 0}, 8, true},
+ {{nullptr, 254, true, 0}, 8, true},
+ {{nullptr, 255, true, 0}, 8, true},
+ {{nullptr, 256, true, 0}, 8, true},
+ {{nullptr, 257, true, 0}, 8, true},
+
+ {{nullptr, 4096 - 2, true, 0}, 8, true},
+ {{nullptr, 4096 - 1, true, 0}, 8, true},
+ {{nullptr, 4096, true, 0}, 8, false},
+ {{nullptr, 4096 + 1, true, 0}, 8, false},
+
+};
+} // namespace
+
+TEST(AddressingModes, AddressingModes) {
+ LLVMInitializeAArch64TargetInfo();
+ LLVMInitializeAArch64Target();
+ LLVMInitializeAArch64TargetMC();
+
+ std::string Error;
+ auto TT = Triple::normalize("aarch64");
+ const Target *T = TargetRegistry::lookupTarget(TT, Error);
+
+ std::unique_ptr<TargetMachine> TM(
+ T->createTargetMachine(TT, "generic", "", TargetOptions(), std::nullopt,
+ std::nullopt, CodeGenOpt::Default));
+ AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(),
+ TM->getTargetCPU(), TM->getTargetFeatureString(), *TM,
+ true);
+
+ auto *TLI = ST.getTargetLowering();
+ DataLayout DL("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
+ LLVMContext Ctx;
+
+ for (const auto &Test : Tests) {
+ Type *Typ = Type::getIntNTy(Ctx, Test.TypeBits);
+ ASSERT_EQ(TLI->isLegalAddressingMode(DL, Test.AM, Typ, 0), Test.Result);
+ }
+}