1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
|
//===--- HexagonGenMemAbsolute.cpp - Generate Load/Store Set Absolute ---===//
//
// 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
//
//===----------------------------------------------------------------------===//
// This pass traverses through all the basic blocks in a function and converts
// an indexed load/store with offset "0" to a absolute-set load/store
// instruction as long as the use of the register in the new instruction
// dominates the rest of the uses and there are more than 2 uses.
#include "HexagonTargetMachine.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#define DEBUG_TYPE "hexagon-abs"
using namespace llvm;
STATISTIC(HexagonNumLoadAbsConversions,
"Number of Load instructions converted to absolute-set form");
STATISTIC(HexagonNumStoreAbsConversions,
"Number of Store instructions converted to absolute-set form");
namespace llvm {
FunctionPass *createHexagonGenMemAbsolute();
void initializeHexagonGenMemAbsolutePass(PassRegistry &Registry);
} // namespace llvm
namespace {
class HexagonGenMemAbsolute : public MachineFunctionPass {
const HexagonInstrInfo *TII;
MachineRegisterInfo *MRI;
const TargetRegisterInfo *TRI;
public:
static char ID;
HexagonGenMemAbsolute() : MachineFunctionPass(ID), TII(0), MRI(0), TRI(0) {
initializeHexagonGenMemAbsolutePass(*PassRegistry::getPassRegistry());
}
StringRef getPassName() const override {
return "Hexagon Generate Load/Store Set Absolute Address Instruction";
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
MachineFunctionPass::getAnalysisUsage(AU);
AU.addRequired<MachineDominatorTreeWrapperPass>();
AU.addPreserved<MachineDominatorTreeWrapperPass>();
}
bool runOnMachineFunction(MachineFunction &Fn) override;
private:
static bool isValidIndexedLoad(int &Opcode, int &NewOpcode);
static bool isValidIndexedStore(int &Opcode, int &NewOpcode);
};
} // namespace
char HexagonGenMemAbsolute::ID = 0;
INITIALIZE_PASS(HexagonGenMemAbsolute, "hexagon-gen-load-absolute",
"Hexagon Generate Load/Store Set Absolute Address Instruction",
false, false)
bool HexagonGenMemAbsolute::runOnMachineFunction(MachineFunction &Fn) {
if (skipFunction(Fn.getFunction()))
return false;
TII = Fn.getSubtarget<HexagonSubtarget>().getInstrInfo();
MRI = &Fn.getRegInfo();
TRI = Fn.getRegInfo().getTargetRegisterInfo();
MachineDominatorTree &MDT =
getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
// Loop over all of the basic blocks
for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
MBBb != MBBe; ++MBBb) {
MachineBasicBlock *MBB = &*MBBb;
// Traverse the basic block
for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end();
++MII) {
MachineInstr *MI = &*MII;
int Opc = MI->getOpcode();
if (Opc != Hexagon::CONST32 && Opc != Hexagon::A2_tfrsi)
continue;
const MachineOperand &MO = MI->getOperand(0);
if (!MO.isReg() || !MO.isDef())
continue;
unsigned DstReg = MO.getReg();
if (MRI->use_nodbg_empty(DstReg))
continue;
typedef MachineRegisterInfo::use_nodbg_iterator use_iterator;
use_iterator NextUseMI = MRI->use_nodbg_begin(DstReg);
MachineInstr *NextMI = NextUseMI->getParent();
int NextOpc = NextMI->getOpcode();
int NewOpc;
bool IsLoad = isValidIndexedLoad(NextOpc, NewOpc);
if (!IsLoad && !isValidIndexedStore(NextOpc, NewOpc))
continue;
// Base and Offset positions for load and store instructions
// Load R(dest), R(base), Imm -> R(dest) = mem(R(base) + Imm)
// Store R(base), Imm, R (src) -> mem(R(base) + Imm) = R(src)
unsigned BaseRegPos, ImmPos, RegPos;
if (!TII->getBaseAndOffsetPosition(*NextMI, BaseRegPos, ImmPos))
continue;
RegPos = IsLoad ? 0 : 2;
bool IsGlobal = MI->getOperand(1).isGlobal();
if (!MI->getOperand(1).isImm() && !IsGlobal)
continue;
const MachineOperand *BaseOp = nullptr;
int64_t Offset;
bool Scalable;
TII->getMemOperandWithOffset(*NextMI, BaseOp, Offset, Scalable, TRI);
// Ensure BaseOp is non-null and register type.
if (!BaseOp || !BaseOp->isReg())
continue;
if (Scalable)
continue;
unsigned BaseReg = BaseOp->getReg();
if ((DstReg != BaseReg) || (Offset != 0))
continue;
const MachineOperand &MO0 = NextMI->getOperand(RegPos);
if (!MO0.isReg())
continue;
unsigned LoadStoreReg = MO0.getReg();
// Store: Bail out if the src and base are same (def and use on same
// register).
if (LoadStoreReg == BaseReg)
continue;
// Insert the absolute-set instruction "I" only if the use of the
// BaseReg in "I" dominates the rest of the uses of BaseReg and if
// there are more than 2 uses of this BaseReg.
bool Dominates = true;
unsigned Counter = 0;
for (use_iterator I = NextUseMI, E = MRI->use_nodbg_end(); I != E; ++I) {
Counter++;
if (!MDT.dominates(NextMI, I->getParent()))
Dominates = false;
}
if ((!Dominates) || (Counter < 3))
continue;
// If we reach here, we have met all the conditions required for the
// replacement of the absolute instruction.
LLVM_DEBUG({
dbgs() << "Found a pair of instructions for absolute-set "
<< (IsLoad ? "load" : "store") << "\n";
dbgs() << *MI;
dbgs() << *NextMI;
});
MachineBasicBlock *ParentBlock = NextMI->getParent();
MachineInstrBuilder MIB;
if (IsLoad) { // Insert absolute-set load instruction
++HexagonNumLoadAbsConversions;
MIB = BuildMI(*ParentBlock, NextMI, NextMI->getDebugLoc(),
TII->get(NewOpc), LoadStoreReg)
.addReg(DstReg, RegState::Define);
} else { // Insert absolute-set store instruction
++HexagonNumStoreAbsConversions;
MIB = BuildMI(*ParentBlock, NextMI, NextMI->getDebugLoc(),
TII->get(NewOpc), DstReg);
}
MachineOperand ImmOperand = MI->getOperand(1);
if (IsGlobal)
MIB.addGlobalAddress(ImmOperand.getGlobal(), ImmOperand.getOffset(),
ImmOperand.getTargetFlags());
else
MIB.addImm(ImmOperand.getImm());
if (IsLoad)
MIB->getOperand(0).setSubReg(MO0.getSubReg());
else
MIB.addReg(LoadStoreReg, 0, MO0.getSubReg());
LLVM_DEBUG(dbgs() << "Replaced with " << *MIB << "\n");
// Erase the instructions that got replaced.
MII = MBB->erase(MI);
--MII;
NextMI->getParent()->erase(NextMI);
}
}
return true;
}
bool HexagonGenMemAbsolute::isValidIndexedLoad(int &Opc, int &NewOpc) {
bool Result = true;
switch (Opc) {
case Hexagon::L2_loadrb_io:
NewOpc = Hexagon::L4_loadrb_ap;
break;
case Hexagon::L2_loadrh_io:
NewOpc = Hexagon::L4_loadrh_ap;
break;
case Hexagon::L2_loadri_io:
NewOpc = Hexagon::L4_loadri_ap;
break;
case Hexagon::L2_loadrd_io:
NewOpc = Hexagon::L4_loadrd_ap;
break;
case Hexagon::L2_loadruh_io:
NewOpc = Hexagon::L4_loadruh_ap;
break;
case Hexagon::L2_loadrub_io:
NewOpc = Hexagon::L4_loadrub_ap;
break;
default:
Result = false;
}
return Result;
}
bool HexagonGenMemAbsolute::isValidIndexedStore(int &Opc, int &NewOpc) {
bool Result = true;
switch (Opc) {
case Hexagon::S2_storerd_io:
NewOpc = Hexagon::S4_storerd_ap;
break;
case Hexagon::S2_storeri_io:
NewOpc = Hexagon::S4_storeri_ap;
break;
case Hexagon::S2_storerh_io:
NewOpc = Hexagon::S4_storerh_ap;
break;
case Hexagon::S2_storerb_io:
NewOpc = Hexagon::S4_storerb_ap;
break;
default:
Result = false;
}
return Result;
}
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
FunctionPass *llvm::createHexagonGenMemAbsolute() {
return new HexagonGenMemAbsolute();
}
|