[llvm] r356606 - [ARC] Add ARCOptAddrMode pass to generate postincrement loads/stores.
Pete Couperus via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 20 13:06:21 PDT 2019
Author: petecoup
Date: Wed Mar 20 13:06:21 2019
New Revision: 356606
URL: http://llvm.org/viewvc/llvm-project?rev=356606&view=rev
Log:
[ARC] Add ARCOptAddrMode pass to generate postincrement loads/stores.
Build on newly introduced ARC postincrement loads/stores from r356200.
Patch By Denis Antrushin! <denis at synopsys.com>
Differential Revision: https://reviews.llvm.org/D59409
Added:
llvm/trunk/lib/Target/ARC/ARCOptAddrMode.cpp
llvm/trunk/test/CodeGen/ARC/addrmode.ll
Modified:
llvm/trunk/lib/Target/ARC/ARC.h
llvm/trunk/lib/Target/ARC/ARCFrameLowering.cpp
llvm/trunk/lib/Target/ARC/ARCTargetMachine.cpp
llvm/trunk/lib/Target/ARC/CMakeLists.txt
Modified: llvm/trunk/lib/Target/ARC/ARC.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARC/ARC.h?rev=356606&r1=356605&r2=356606&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARC/ARC.h (original)
+++ llvm/trunk/lib/Target/ARC/ARC.h Wed Mar 20 13:06:21 2019
@@ -25,6 +25,7 @@ class ARCTargetMachine;
FunctionPass *createARCISelDag(ARCTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createARCExpandPseudosPass();
+FunctionPass *createARCOptAddrMode();
FunctionPass *createARCBranchFinalizePass();
} // end namespace llvm
Modified: llvm/trunk/lib/Target/ARC/ARCFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARC/ARCFrameLowering.cpp?rev=356606&r1=356605&r2=356606&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARC/ARCFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARC/ARCFrameLowering.cpp Wed Mar 20 13:06:21 2019
@@ -311,8 +311,8 @@ void ARCFrameLowering::emitEpilogue(Mach
// Now, pop fp if necessary.
if (hasFP(MF)) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
- .addReg(ARC::SP, RegState::Define)
.addReg(ARC::FP, RegState::Define)
+ .addReg(ARC::SP, RegState::Define)
.addReg(ARC::SP)
.addImm(4);
}
Added: llvm/trunk/lib/Target/ARC/ARCOptAddrMode.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARC/ARCOptAddrMode.cpp?rev=356606&view=auto
==============================================================================
--- llvm/trunk/lib/Target/ARC/ARCOptAddrMode.cpp (added)
+++ llvm/trunk/lib/Target/ARC/ARCOptAddrMode.cpp Wed Mar 20 13:06:21 2019
@@ -0,0 +1,507 @@
+//===- ARCOptAddrMode.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This pass folds LD/ST + ADD pairs into Pre/Post-increment form of
+/// load/store instructions.
+//===----------------------------------------------------------------------===//
+
+#include "ARC.h"
+#define GET_INSTRMAP_INFO
+#include "ARCInstrInfo.h"
+#include "ARCTargetMachine.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+#define OPTADDRMODE_DESC "ARC load/store address mode"
+#define OPTADDRMODE_NAME "arc-addr-mode"
+#define DEBUG_TYPE "arc-addr-mode"
+
+namespace llvm {
+FunctionPass *createARCOptAddrMode();
+void initializeARCOptAddrModePass(PassRegistry &);
+} // end namespace llvm
+
+namespace {
+class ARCOptAddrMode : public MachineFunctionPass {
+public:
+ static char ID;
+
+ ARCOptAddrMode() : MachineFunctionPass(ID) {}
+
+ StringRef getPassName() const override { return OPTADDRMODE_DESC; }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<MachineDominatorTree>();
+ AU.addPreserved<MachineDominatorTree>();
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+private:
+ const ARCSubtarget *AST = nullptr;
+ const ARCInstrInfo *AII = nullptr;
+ MachineRegisterInfo *MRI = nullptr;
+ MachineDominatorTree *MDT = nullptr;
+
+ // Tries to combine \p Ldst with increment of its base register to form
+ // single post-increment instruction.
+ MachineInstr *tryToCombine(MachineInstr &Ldst);
+
+ // Returns true if result of \p Add is not used before \p Ldst
+ bool noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
+ const MachineInstr *Ldst);
+
+ // Returns true if load/store instruction \p Ldst can be hoisted up to
+ // instruction \p To
+ bool canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);
+
+ // Returns true if load/store instruction \p Ldst can be sunk down
+ // to instruction \p To
+ bool canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);
+
+ // Check if instructions \p Ldst and \p Add can be moved to become adjacent
+ // If they can return instruction which need not to move.
+ // If \p Uses is not null, fill it with instructions after \p Ldst which use
+ // \p Ldst's base register
+ MachineInstr *canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
+ SmallVectorImpl<MachineInstr *> *Uses);
+
+ // Returns true if all instruction in \p Uses array can be adjusted
+ // to accomodate increment of register \p BaseReg by \p Incr
+ bool canFixPastUses(const ArrayRef<MachineInstr *> &Uses,
+ MachineOperand &Incr, unsigned BaseReg);
+
+ // Update all instructions in \p Uses to accomodate increment
+ // of \p BaseReg by \p Offset
+ void fixPastUses(ArrayRef<MachineInstr *> Uses, unsigned BaseReg,
+ int64_t Offset);
+
+ // Change instruction \p Ldst to postincrement form.
+ // \p NewBase is register to hold update base value
+ // \p NewOffset is instruction's new offset
+ void changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
+ unsigned NewBase, MachineOperand &NewOffset);
+
+ bool processBasicBlock(MachineBasicBlock &MBB);
+};
+
+} // end anonymous namespace
+
+char ARCOptAddrMode::ID = 0;
+INITIALIZE_PASS_BEGIN(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,
+ false)
+INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
+INITIALIZE_PASS_END(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,
+ false)
+
+// Return true if \p Off can be used as immediate offset
+// operand of load/store instruction (S9 literal)
+static bool isValidLoadStoreOffset(int64_t Off) { return isInt<9>(Off); }
+
+// Return true if \p Off can be used as immediate operand of
+// ADD/SUB instruction (U6 literal)
+static bool isValidIncrementOffset(int64_t Off) { return isUInt<6>(Off); }
+
+static bool isAddConstantOp(const MachineInstr &MI, int64_t &Amount) {
+ int64_t Sign = 1;
+ switch (MI.getOpcode()) {
+ case ARC::SUB_rru6:
+ Sign = -1;
+ // LLVM_FALLTHROUGH
+ case ARC::ADD_rru6:
+ assert(MI.getOperand(2).isImm() && "Expected immediate operand");
+ Amount = Sign * MI.getOperand(2).getImm();
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Return true if \p MI dominates of uses of virtual register \p VReg
+static bool dominatesAllUsesOf(const MachineInstr *MI, unsigned VReg,
+ MachineDominatorTree *MDT,
+ MachineRegisterInfo *MRI) {
+
+ assert(TargetRegisterInfo::isVirtualRegister(VReg) &&
+ "Expected virtual register!");
+
+ for (auto it = MRI->use_nodbg_begin(VReg), end = MRI->use_nodbg_end();
+ it != end; ++it) {
+ MachineInstr *User = it->getParent();
+ if (User->isPHI()) {
+ unsigned BBOperandIdx = User->getOperandNo(&*it) + 1;
+ MachineBasicBlock *MBB = User->getOperand(BBOperandIdx).getMBB();
+ if (MBB->empty()) {
+ const MachineBasicBlock *InstBB = MI->getParent();
+ assert(InstBB != MBB && "Instruction found in empty MBB");
+ if (!MDT->dominates(InstBB, MBB))
+ return false;
+ continue;
+ }
+ User = &*MBB->rbegin();
+ }
+
+ if (!MDT->dominates(MI, User))
+ return false;
+ }
+ return true;
+}
+
+// Return true if \p MI is load/store instruction with immediate offset
+// which can be adjusted by \p Disp
+static bool isLoadStoreThatCanHandleDisplacement(const TargetInstrInfo *TII,
+ const MachineInstr &MI,
+ int64_t Disp) {
+ unsigned BasePos, OffPos;
+ if (!TII->getBaseAndOffsetPosition(MI, BasePos, OffPos))
+ return false;
+ const MachineOperand &MO = MI.getOperand(OffPos);
+ if (!MO.isImm())
+ return false;
+ int64_t Offset = MO.getImm() + Disp;
+ return isValidLoadStoreOffset(Offset);
+}
+
+bool ARCOptAddrMode::noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
+ const MachineInstr *Ldst) {
+ unsigned R = Add->getOperand(0).getReg();
+ return dominatesAllUsesOf(Ldst, R, MDT, MRI);
+}
+
+MachineInstr *ARCOptAddrMode::tryToCombine(MachineInstr &Ldst) {
+ assert((Ldst.mayLoad() || Ldst.mayStore()) && "LD/ST instruction expected");
+
+ unsigned BasePos, OffsetPos;
+
+ LLVM_DEBUG(dbgs() << "[ABAW] tryToCombine " << Ldst);
+ if (!AII->getBaseAndOffsetPosition(Ldst, BasePos, OffsetPos)) {
+ LLVM_DEBUG(dbgs() << "[ABAW] Not a recognized load/store\n");
+ return nullptr;
+ }
+
+ MachineOperand &Base = Ldst.getOperand(BasePos);
+ MachineOperand &Offset = Ldst.getOperand(OffsetPos);
+
+ assert(Base.isReg() && "Base operand must be register");
+ if (!Offset.isImm()) {
+ LLVM_DEBUG(dbgs() << "[ABAW] Offset is not immediate\n");
+ return nullptr;
+ }
+
+ unsigned B = Base.getReg();
+ if (TargetRegisterInfo::isStackSlot(B) ||
+ !TargetRegisterInfo::isVirtualRegister(B)) {
+ LLVM_DEBUG(dbgs() << "[ABAW] Base is not VReg\n");
+ return nullptr;
+ }
+
+ // TODO: try to generate address preincrement
+ if (Offset.getImm() != 0) {
+ LLVM_DEBUG(dbgs() << "[ABAW] Non-zero offset\n");
+ return nullptr;
+ }
+
+ for (auto &Add : MRI->use_nodbg_instructions(B)) {
+ int64_t Incr;
+ if (!isAddConstantOp(Add, Incr))
+ continue;
+ if (!isValidLoadStoreOffset(Incr))
+ continue;
+
+ SmallVector<MachineInstr *, 8> Uses;
+ MachineInstr *MoveTo = canJoinInstructions(&Ldst, &Add, &Uses);
+
+ if (!MoveTo)
+ continue;
+
+ if (!canFixPastUses(Uses, Add.getOperand(2), B))
+ continue;
+
+ LLVM_DEBUG(MachineInstr *First = &Ldst; MachineInstr *Last = &Add;
+ if (MDT->dominates(Last, First)) std::swap(First, Last);
+ dbgs() << "[ABAW] Instructions " << *First << " and " << *Last
+ << " combined\n";
+
+ );
+
+ MachineInstr *Result = Ldst.getNextNode();
+ if (MoveTo == &Add) {
+ Ldst.removeFromParent();
+ Add.getParent()->insertAfter(Add.getIterator(), &Ldst);
+ }
+ if (Result == &Add)
+ Result = Result->getNextNode();
+
+ fixPastUses(Uses, B, Incr);
+
+ int NewOpcode = ARC::getPostIncOpcode(Ldst.getOpcode());
+ assert(NewOpcode > 0 && "No postincrement form found");
+ unsigned NewBaseReg = Add.getOperand(0).getReg();
+ changeToAddrMode(Ldst, NewOpcode, NewBaseReg, Add.getOperand(2));
+ Add.eraseFromParent();
+
+ return Result;
+ }
+ return nullptr;
+}
+
+MachineInstr *
+ARCOptAddrMode::canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
+ SmallVectorImpl<MachineInstr *> *Uses) {
+ assert(Ldst && Add && "NULL instruction passed");
+
+ MachineInstr *First = Add;
+ MachineInstr *Last = Ldst;
+ if (MDT->dominates(Ldst, Add))
+ std::swap(First, Last);
+ else if (!MDT->dominates(Add, Ldst))
+ return nullptr;
+
+ LLVM_DEBUG(dbgs() << "canJoinInstructions: " << *First << *Last);
+
+ unsigned BasePos, OffPos;
+
+ if (!AII->getBaseAndOffsetPosition(*Ldst, BasePos, OffPos)) {
+ LLVM_DEBUG(
+ dbgs()
+ << "[canJoinInstructions] Cannot determine base/offset position\n");
+ return nullptr;
+ }
+
+ unsigned BaseReg = Ldst->getOperand(BasePos).getReg();
+
+ // prohibit this:
+ // v1 = add v0, c
+ // st v1, [v0, 0]
+ // and this
+ // st v0, [v0, 0]
+ // v1 = add v0, c
+ if (Ldst->mayStore() && Ldst->getOperand(0).isReg()) {
+ unsigned StReg = Ldst->getOperand(0).getReg();
+ if (Add->getOperand(0).getReg() == StReg || BaseReg == StReg) {
+ LLVM_DEBUG(dbgs() << "[canJoinInstructions] Store uses result of Add\n");
+ return nullptr;
+ }
+ }
+
+ SmallVector<MachineInstr *, 4> UsesAfterLdst;
+ SmallVector<MachineInstr *, 4> UsesAfterAdd;
+ for (MachineInstr &MI : MRI->use_nodbg_instructions(BaseReg)) {
+ if (&MI == Ldst || &MI == Add)
+ continue;
+ if (&MI != Add && MDT->dominates(Ldst, &MI))
+ UsesAfterLdst.push_back(&MI);
+ else if (!MDT->dominates(&MI, Ldst))
+ return nullptr;
+ if (MDT->dominates(Add, &MI))
+ UsesAfterAdd.push_back(&MI);
+ }
+
+ MachineInstr *Result = nullptr;
+
+ if (First == Add) {
+ // n = add b, i
+ // ...
+ // x = ld [b, o] or x = ld [n, o]
+
+ if (noUseOfAddBeforeLoadOrStore(First, Last)) {
+ Result = Last;
+ LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can sink Add down to Ldst\n");
+ } else if (canHoistLoadStoreTo(Ldst, Add)) {
+ Result = First;
+ LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Ldst to Add\n");
+ }
+ } else {
+ // x = ld [b, o]
+ // ...
+ // n = add b, i
+ Result = First;
+ LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Add to Ldst\n");
+ }
+ if (Result && Uses)
+ *Uses = (Result == Ldst) ? UsesAfterLdst : UsesAfterAdd;
+ return Result;
+}
+
+bool ARCOptAddrMode::canFixPastUses(const ArrayRef<MachineInstr *> &Uses,
+ MachineOperand &Incr, unsigned BaseReg) {
+
+ assert(Incr.isImm() && "Expected immediate increment");
+ int64_t NewOffset = Incr.getImm();
+ for (MachineInstr *MI : Uses) {
+ int64_t Dummy;
+ if (isAddConstantOp(*MI, Dummy)) {
+ if (isValidIncrementOffset(Dummy + NewOffset))
+ continue;
+ return false;
+ }
+ if (isLoadStoreThatCanHandleDisplacement(AII, *MI, -NewOffset))
+ continue;
+ LLVM_DEBUG(dbgs() << "Instruction cannot handle displacement " << -NewOffset
+ << ": " << *MI);
+ return false;
+ }
+ return true;
+}
+
+void ARCOptAddrMode::fixPastUses(ArrayRef<MachineInstr *> Uses,
+ unsigned NewBase, int64_t NewOffset) {
+
+ for (MachineInstr *MI : Uses) {
+ int64_t Amount;
+ unsigned BasePos, OffPos;
+ if (isAddConstantOp(*MI, Amount)) {
+ NewOffset += Amount;
+ assert(isValidIncrementOffset(NewOffset) &&
+ "New offset won't fit into ADD instr");
+ BasePos = 1;
+ OffPos = 2;
+ } else if (AII->getBaseAndOffsetPosition(*MI, BasePos, OffPos)) {
+ MachineOperand &MO = MI->getOperand(OffPos);
+ assert(MO.isImm() && "expected immediate operand");
+ NewOffset += MO.getImm();
+ assert(isValidLoadStoreOffset(NewOffset) &&
+ "New offset won't fit into LD/ST");
+ } else
+ llvm_unreachable("unexpected instruction");
+
+ MI->getOperand(BasePos).setReg(NewBase);
+ MI->getOperand(OffPos).setImm(NewOffset);
+ }
+}
+
+bool ARCOptAddrMode::canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {
+ if (Ldst->getParent() != To->getParent())
+ return false;
+ MachineBasicBlock::const_iterator MI(To), ME(Ldst),
+ End(Ldst->getParent()->end());
+
+ bool IsStore = Ldst->mayStore();
+ for (; MI != ME && MI != End; ++MI) {
+ if (MI->isDebugValue())
+ continue;
+ if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||
+ MI->hasUnmodeledSideEffects())
+ return false;
+ if (IsStore && MI->mayLoad())
+ return false;
+ }
+
+ for (auto &O : Ldst->explicit_operands()) {
+ if (!O.isReg() || !O.isUse())
+ continue;
+ MachineInstr *OpDef = MRI->getVRegDef(O.getReg());
+ if (!OpDef || !MDT->dominates(OpDef, To))
+ return false;
+ }
+ return true;
+}
+
+bool ARCOptAddrMode::canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {
+ // Can only sink load/store within same BB
+ if (Ldst->getParent() != To->getParent())
+ return false;
+ MachineBasicBlock::const_iterator MI(Ldst), ME(To),
+ End(Ldst->getParent()->end());
+
+ bool IsStore = Ldst->mayStore();
+ bool IsLoad = Ldst->mayLoad();
+
+ unsigned ValReg = IsLoad ? Ldst->getOperand(0).getReg() : 0;
+ for (; MI != ME && MI != End; ++MI) {
+ if (MI->isDebugValue())
+ continue;
+ if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||
+ MI->hasUnmodeledSideEffects())
+ return false;
+ if (IsStore && MI->mayLoad())
+ return false;
+ if (ValReg && MI->readsVirtualRegister(ValReg))
+ return false;
+ }
+ return true;
+}
+
+void ARCOptAddrMode::changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
+ unsigned NewBase,
+ MachineOperand &NewOffset) {
+ bool IsStore = Ldst.mayStore();
+ unsigned BasePos, OffPos;
+ MachineOperand Src = MachineOperand::CreateImm(0xDEADBEEF);
+ AII->getBaseAndOffsetPosition(Ldst, BasePos, OffPos);
+
+ unsigned BaseReg = Ldst.getOperand(BasePos).getReg();
+
+ Ldst.RemoveOperand(OffPos);
+ Ldst.RemoveOperand(BasePos);
+
+ if (IsStore) {
+ Src = Ldst.getOperand(BasePos - 1);
+ Ldst.RemoveOperand(BasePos - 1);
+ }
+
+ Ldst.setDesc(AST->getInstrInfo()->get(NewOpcode));
+ Ldst.addOperand(MachineOperand::CreateReg(NewBase, true));
+ if (IsStore)
+ Ldst.addOperand(Src);
+ Ldst.addOperand(MachineOperand::CreateReg(BaseReg, false));
+ Ldst.addOperand(NewOffset);
+ LLVM_DEBUG(dbgs() << "[ABAW] New Ldst: " << Ldst);
+}
+
+bool ARCOptAddrMode::processBasicBlock(MachineBasicBlock &MBB) {
+ bool Changed = false;
+ for (auto MI = MBB.begin(), ME = MBB.end(); MI != ME; ++MI) {
+ if (MI->isDebugValue())
+ continue;
+ if (!MI->mayLoad() && !MI->mayStore())
+ continue;
+ if (ARC::getPostIncOpcode(MI->getOpcode()) < 0)
+ continue;
+ MachineInstr *Res = tryToCombine(*MI);
+ if (Res) {
+ Changed = true;
+ // Res points to the next instruction. Rewind to process it
+ MI = std::prev(Res->getIterator());
+ }
+ }
+ return Changed;
+}
+
+bool ARCOptAddrMode::runOnMachineFunction(MachineFunction &MF) {
+ if (skipFunction(MF.getFunction()))
+ return false;
+
+ AST = &MF.getSubtarget<ARCSubtarget>();
+ AII = AST->getInstrInfo();
+ MRI = &MF.getRegInfo();
+ MDT = &getAnalysis<MachineDominatorTree>();
+
+ bool Changed = false;
+ for (auto &MBB : MF)
+ Changed |= processBasicBlock(MBB);
+ return Changed;
+}
+
+//===----------------------------------------------------------------------===//
+// Public Constructor Functions
+//===----------------------------------------------------------------------===//
+
+FunctionPass *llvm::createARCOptAddrMode() { return new ARCOptAddrMode(); }
Modified: llvm/trunk/lib/Target/ARC/ARCTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARC/ARCTargetMachine.cpp?rev=356606&r1=356605&r2=356606&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARC/ARCTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/ARC/ARCTargetMachine.cpp Wed Mar 20 13:06:21 2019
@@ -74,7 +74,10 @@ bool ARCPassConfig::addInstSelector() {
void ARCPassConfig::addPreEmitPass() { addPass(createARCBranchFinalizePass()); }
-void ARCPassConfig::addPreRegAlloc() { addPass(createARCExpandPseudosPass()); }
+void ARCPassConfig::addPreRegAlloc() {
+ addPass(createARCExpandPseudosPass());
+ addPass(createARCOptAddrMode());
+}
// Force static initialization.
extern "C" void LLVMInitializeARCTarget() {
Modified: llvm/trunk/lib/Target/ARC/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARC/CMakeLists.txt?rev=356606&r1=356605&r2=356606&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARC/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/ARC/CMakeLists.txt Wed Mar 20 13:06:21 2019
@@ -20,6 +20,7 @@ add_llvm_target(ARCCodeGen
ARCISelLowering.cpp
ARCMachineFunctionInfo.cpp
ARCMCInstLower.cpp
+ ARCOptAddrMode.cpp
ARCRegisterInfo.cpp
ARCSubtarget.cpp
ARCTargetMachine.cpp
Added: llvm/trunk/test/CodeGen/ARC/addrmode.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARC/addrmode.ll?rev=356606&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/ARC/addrmode.ll (added)
+++ llvm/trunk/test/CodeGen/ARC/addrmode.ll Wed Mar 20 13:06:21 2019
@@ -0,0 +1,68 @@
+; RUN: llc -march=arc < %s | FileCheck %s
+
+; CHECK-LABEL: copy
+; CHECK-NOT: add
+define void @copy(i8* inreg nocapture %p, i8* inreg nocapture readonly %q) {
+entry:
+ br label %while.cond
+
+while.cond: ; preds = %while.cond, %entry
+ %p.addr.0 = phi i8* [ %p, %entry ], [ %incdec.ptr1, %while.cond ]
+ %q.addr.0 = phi i8* [ %q, %entry ], [ %incdec.ptr, %while.cond ]
+ %incdec.ptr = getelementptr inbounds i8, i8* %q.addr.0, i32 1
+ %0 = load i8, i8* %q.addr.0, align 1
+ %incdec.ptr1 = getelementptr inbounds i8, i8* %p.addr.0, i32 1
+ store i8 %0, i8* %p.addr.0, align 1
+ %tobool = icmp eq i8 %0, 0
+ br i1 %tobool, label %while.end, label %while.cond
+
+while.end: ; preds = %while.cond
+ ret void
+}
+
+
+%struct._llist = type { %struct._llist*, %struct._llist*, i32 }
+
+; CHECK-LABEL: neg1
+; CHECK-NOT: std.ab
+define void @neg1(i8* inreg nocapture %a, i8* inreg nocapture readonly %b, i32 inreg %n) {
+entry:
+ %cmp6 = icmp sgt i32 %n, 0
+ br i1 %cmp6, label %for.body, label %for.cond.cleanup
+
+for.cond.cleanup:
+ ret void
+
+for.body:
+ %i.07 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
+ %arrayidx = getelementptr inbounds i8, i8* %b, i32 %i.07
+ %0 = load i8, i8* %arrayidx, align 1
+ %mul = mul nuw nsw i32 %i.07, 257
+ %arrayidx1 = getelementptr inbounds i8, i8* %a, i32 %mul
+ store i8 %0, i8* %arrayidx1, align 1
+ %inc = add nuw nsw i32 %i.07, 1
+ %exitcond = icmp eq i32 %inc, %n
+ br i1 %exitcond, label %for.cond.cleanup, label %for.body
+}
+
+; CHECK-LABEL: neg2
+; CHECK-NOT: st.ab
+define void @neg2(%struct._llist* inreg %a, i32 inreg %n) {
+entry:
+ %cmp13 = icmp sgt i32 %n, 0
+ br i1 %cmp13, label %for.body, label %for.cond.cleanup
+
+for.cond.cleanup:
+ ret void
+
+for.body:
+ %i.014 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
+ %arrayidx = getelementptr inbounds %struct._llist, %struct._llist* %a, i32 %i.014
+ %next = getelementptr inbounds %struct._llist, %struct._llist* %arrayidx, i32 0, i32 0
+ store %struct._llist* %arrayidx, %struct._llist** %next, align 4
+ %prev = getelementptr inbounds %struct._llist, %struct._llist* %a, i32 %i.014, i32 1
+ store %struct._llist* %arrayidx, %struct._llist** %prev, align 4
+ %inc = add nuw nsw i32 %i.014, 1
+ %exitcond = icmp eq i32 %inc, %n
+ br i1 %exitcond, label %for.cond.cleanup, label %for.body
+}
More information about the llvm-commits
mailing list