summaryrefslogtreecommitdiff
path: root/lib/Target/Hexagon/HexagonExpandCondsets.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Hexagon/HexagonExpandCondsets.cpp')
-rw-r--r--lib/Target/Hexagon/HexagonExpandCondsets.cpp154
1 files changed, 87 insertions, 67 deletions
diff --git a/lib/Target/Hexagon/HexagonExpandCondsets.cpp b/lib/Target/Hexagon/HexagonExpandCondsets.cpp
index a2f6dd68c1a1..c2feaf5737b2 100644
--- a/lib/Target/Hexagon/HexagonExpandCondsets.cpp
+++ b/lib/Target/Hexagon/HexagonExpandCondsets.cpp
@@ -1,4 +1,4 @@
-//===--- HexagonExpandCondsets.cpp ----------------------------------------===//
+//===- HexagonExpandCondsets.cpp ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -17,33 +17,33 @@
//
// Liveness tracking aside, the main functionality of this pass is divided
// into two steps. The first step is to replace an instruction
-// vreg0 = C2_mux vreg1, vreg2, vreg3
+// %0 = C2_mux %1, %2, %3
// with a pair of conditional transfers
-// vreg0 = A2_tfrt vreg1, vreg2
-// vreg0 = A2_tfrf vreg1, vreg3
+// %0 = A2_tfrt %1, %2
+// %0 = A2_tfrf %1, %3
// It is the intention that the execution of this pass could be terminated
// after this step, and the code generated would be functionally correct.
//
-// If the uses of the source values vreg1 and vreg2 are kills, and their
+// If the uses of the source values %1 and %2 are kills, and their
// definitions are predicable, then in the second step, the conditional
// transfers will then be rewritten as predicated instructions. E.g.
-// vreg0 = A2_or vreg1, vreg2
-// vreg3 = A2_tfrt vreg99, vreg0<kill>
+// %0 = A2_or %1, %2
+// %3 = A2_tfrt %99, killed %0
// will be rewritten as
-// vreg3 = A2_port vreg99, vreg1, vreg2
+// %3 = A2_port %99, %1, %2
//
// This replacement has two variants: "up" and "down". Consider this case:
-// vreg0 = A2_or vreg1, vreg2
+// %0 = A2_or %1, %2
// ... [intervening instructions] ...
-// vreg3 = A2_tfrt vreg99, vreg0<kill>
+// %3 = A2_tfrt %99, killed %0
// variant "up":
-// vreg3 = A2_port vreg99, vreg1, vreg2
-// ... [intervening instructions, vreg0->vreg3] ...
+// %3 = A2_port %99, %1, %2
+// ... [intervening instructions, %0->vreg3] ...
// [deleted]
// variant "down":
// [deleted]
// ... [intervening instructions] ...
-// vreg3 = A2_port vreg99, vreg1, vreg2
+// %3 = A2_port %99, %1, %2
//
// Both, one or none of these variants may be valid, and checks are made
// to rule out inapplicable variants.
@@ -51,13 +51,13 @@
// As an additional optimization, before either of the two steps above is
// executed, the pass attempts to coalesce the target register with one of
// the source registers, e.g. given an instruction
-// vreg3 = C2_mux vreg0, vreg1, vreg2
-// vreg3 will be coalesced with either vreg1 or vreg2. If this succeeds,
+// %3 = C2_mux %0, %1, %2
+// %3 will be coalesced with either %1 or %2. If this succeeds,
// the instruction would then be (for example)
-// vreg3 = C2_mux vreg0, vreg3, vreg2
+// %3 = C2_mux %0, %3, %2
// and, under certain circumstances, this could result in only one predicated
// instruction:
-// vreg3 = A2_tfrf vreg0, vreg2
+// %3 = A2_tfrf %0, %2
//
// Splitting a definition of a register into two predicated transfers
@@ -65,18 +65,18 @@
// will see both instructions as actual definitions, and will mark the
// first one as dead. The definition is not actually dead, and this
// situation will need to be fixed. For example:
-// vreg1<def,dead> = A2_tfrt ... ; marked as dead
-// vreg1<def> = A2_tfrf ...
+// dead %1 = A2_tfrt ... ; marked as dead
+// %1 = A2_tfrf ...
//
// Since any of the individual predicated transfers may end up getting
// removed (in case it is an identity copy), some pre-existing def may
// be marked as dead after live interval recomputation:
-// vreg1<def,dead> = ... ; marked as dead
+// dead %1 = ... ; marked as dead
// ...
-// vreg1<def> = A2_tfrf ... ; if A2_tfrt is removed
-// This case happens if vreg1 was used as a source in A2_tfrt, which means
+// %1 = A2_tfrf ... ; if A2_tfrt is removed
+// This case happens if %1 was used as a source in A2_tfrt, which means
// that is it actually live at the A2_tfrf, and so the now dead definition
-// of vreg1 will need to be updated to non-dead at some point.
+// of %1 will need to be updated to non-dead at some point.
//
// This issue could be remedied by adding implicit uses to the predicated
// transfers, but this will create a problem with subsequent predication,
@@ -87,12 +87,13 @@
// to be added, and updating the live ranges will be more involved.
#include "HexagonInstrInfo.h"
+#include "HexagonRegisterInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/LiveInterval.h"
-#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -102,13 +103,16 @@
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SlotIndexes.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/Function.h"
+#include "llvm/MC/LaneBitmask.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetRegisterInfo.h"
#include <cassert>
#include <iterator>
#include <set>
@@ -136,10 +140,7 @@ namespace {
public:
static char ID;
- HexagonExpandCondsets() :
- MachineFunctionPass(ID), HII(nullptr), TRI(nullptr), MRI(nullptr),
- LIS(nullptr), CoaLimitActive(false),
- TfrLimitActive(false), CoaCounter(0), TfrCounter(0) {
+ HexagonExpandCondsets() : MachineFunctionPass(ID) {
if (OptCoaLimit.getPosition())
CoaLimitActive = true, CoaLimit = OptCoaLimit;
if (OptTfrLimit.getPosition())
@@ -161,14 +162,17 @@ namespace {
bool runOnMachineFunction(MachineFunction &MF) override;
private:
- const HexagonInstrInfo *HII;
- const TargetRegisterInfo *TRI;
+ const HexagonInstrInfo *HII = nullptr;
+ const TargetRegisterInfo *TRI = nullptr;
MachineDominatorTree *MDT;
- MachineRegisterInfo *MRI;
- LiveIntervals *LIS;
-
- bool CoaLimitActive, TfrLimitActive;
- unsigned CoaLimit, TfrLimit, CoaCounter, TfrCounter;
+ MachineRegisterInfo *MRI = nullptr;
+ LiveIntervals *LIS = nullptr;
+ bool CoaLimitActive = false;
+ bool TfrLimitActive = false;
+ unsigned CoaLimit;
+ unsigned TfrLimit;
+ unsigned CoaCounter = 0;
+ unsigned TfrCounter = 0;
struct RegisterRef {
RegisterRef(const MachineOperand &Op) : Reg(Op.getReg()),
@@ -186,9 +190,10 @@ namespace {
unsigned Reg, Sub;
};
- typedef DenseMap<unsigned,unsigned> ReferenceMap;
+ using ReferenceMap = DenseMap<unsigned, unsigned>;
enum { Sub_Low = 0x1, Sub_High = 0x2, Sub_None = (Sub_Low | Sub_High) };
enum { Exec_Then = 0x10, Exec_Else = 0x20 };
+
unsigned getMaskForSub(unsigned Sub);
bool isCondset(const MachineInstr &MI);
LaneBitmask getLaneMask(unsigned Reg, unsigned Sub);
@@ -484,18 +489,33 @@ void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
if (!HII->isPredicated(*DefI))
continue;
// Construct the set of all necessary implicit uses, based on the def
- // operands in the instruction.
- std::set<RegisterRef> ImpUses;
- for (auto &Op : DefI->operands())
- if (Op.isReg() && Op.isDef() && DefRegs.count(Op))
- ImpUses.insert(Op);
+ // operands in the instruction. We need to tie the implicit uses to
+ // the corresponding defs.
+ std::map<RegisterRef,unsigned> ImpUses;
+ for (unsigned i = 0, e = DefI->getNumOperands(); i != e; ++i) {
+ MachineOperand &Op = DefI->getOperand(i);
+ if (!Op.isReg() || !DefRegs.count(Op))
+ continue;
+ if (Op.isDef()) {
+ ImpUses.insert({Op, i});
+ } else {
+ // This function can be called for the same register with different
+ // lane masks. If the def in this instruction was for the whole
+ // register, we can get here more than once. Avoid adding multiple
+ // implicit uses (or adding an implicit use when an explicit one is
+ // present).
+ ImpUses.erase(Op);
+ }
+ }
if (ImpUses.empty())
continue;
MachineFunction &MF = *DefI->getParent()->getParent();
- for (RegisterRef R : ImpUses)
+ for (std::pair<RegisterRef, unsigned> P : ImpUses) {
+ RegisterRef R = P.first;
MachineInstrBuilder(MF, DefI).addReg(R.Reg, RegState::Implicit, R.Sub);
+ DefI->tieOperands(P.second, DefI->getNumOperands()-1);
+ }
}
-
}
void HexagonExpandCondsets::updateDeadFlags(unsigned Reg) {
@@ -634,7 +654,7 @@ bool HexagonExpandCondsets::split(MachineInstr &MI,
return false;
TfrCounter++;
}
- DEBUG(dbgs() << "\nsplitting BB#" << MI.getParent()->getNumber() << ": "
+ DEBUG(dbgs() << "\nsplitting " << printMBBReference(*MI.getParent()) << ": "
<< MI);
MachineOperand &MD = MI.getOperand(0); // Definition
MachineOperand &MP = MI.getOperand(1); // Predicate register
@@ -740,8 +760,8 @@ MachineInstr *HexagonExpandCondsets::getReachingDefForPred(RegisterRef RD,
if (RR.Reg != RD.Reg)
continue;
// If the "Reg" part agrees, there is still the subregister to check.
- // If we are looking for vreg1:loreg, we can skip vreg1:hireg, but
- // not vreg1 (w/o subregisters).
+ // If we are looking for %1:loreg, we can skip %1:hireg, but
+ // not %1 (w/o subregisters).
if (RR.Sub == RD.Sub)
return MI;
if (RR.Sub == 0 || RD.Sub == 0)
@@ -1051,7 +1071,7 @@ bool HexagonExpandCondsets::predicateInBlock(MachineBasicBlock &B,
bool Done = predicate(*I, (Opc == Hexagon::A2_tfrt), UpdRegs);
if (!Done) {
// If we didn't predicate I, we may need to remove it in case it is
- // an "identity" copy, e.g. vreg1 = A2_tfrt vreg2, vreg1.
+ // an "identity" copy, e.g. %1 = A2_tfrt %2, %1.
if (RegisterRef(I->getOperand(0)) == RegisterRef(I->getOperand(2))) {
for (auto &Op : I->operands())
if (Op.isReg())
@@ -1117,8 +1137,8 @@ bool HexagonExpandCondsets::coalesceRegisters(RegisterRef R1, RegisterRef R2) {
DEBUG(dbgs() << "compatible registers: ("
<< (Overlap ? "overlap" : "disjoint") << ")\n "
- << PrintReg(R1.Reg, TRI, R1.Sub) << " " << L1 << "\n "
- << PrintReg(R2.Reg, TRI, R2.Sub) << " " << L2 << "\n");
+ << printReg(R1.Reg, TRI, R1.Sub) << " " << L1 << "\n "
+ << printReg(R2.Reg, TRI, R2.Sub) << " " << L2 << "\n");
if (R1.Sub || R2.Sub)
return false;
if (Overlap)
@@ -1133,7 +1153,7 @@ bool HexagonExpandCondsets::coalesceRegisters(RegisterRef R1, RegisterRef R2) {
MRI->replaceRegWith(R2.Reg, R1.Reg);
// Move all live segments from L2 to L1.
- typedef DenseMap<VNInfo*,VNInfo*> ValueInfoMap;
+ using ValueInfoMap = DenseMap<VNInfo *, VNInfo *>;
ValueInfoMap VM;
for (LiveInterval::iterator I = L2.begin(), E = L2.end(); I != E; ++I) {
VNInfo *NewVN, *OldVN = I->valno;
@@ -1178,18 +1198,18 @@ bool HexagonExpandCondsets::coalesceSegments(
MachineOperand &S1 = CI->getOperand(2), &S2 = CI->getOperand(3);
bool Done = false;
// Consider this case:
- // vreg1 = instr1 ...
- // vreg2 = instr2 ...
- // vreg0 = C2_mux ..., vreg1, vreg2
- // If vreg0 was coalesced with vreg1, we could end up with the following
+ // %1 = instr1 ...
+ // %2 = instr2 ...
+ // %0 = C2_mux ..., %1, %2
+ // If %0 was coalesced with %1, we could end up with the following
// code:
- // vreg0 = instr1 ...
- // vreg2 = instr2 ...
- // vreg0 = A2_tfrf ..., vreg2
+ // %0 = instr1 ...
+ // %2 = instr2 ...
+ // %0 = A2_tfrf ..., %2
// which will later become:
- // vreg0 = instr1 ...
- // vreg0 = instr2_cNotPt ...
- // i.e. there will be an unconditional definition (instr1) of vreg0
+ // %0 = instr1 ...
+ // %0 = instr2_cNotPt ...
+ // i.e. there will be an unconditional definition (instr1) of %0
// followed by a conditional one. The output dependency was there before
// and it unavoidable, but if instr1 is predicable, we will no longer be
// able to predicate it here.
@@ -1223,7 +1243,7 @@ bool HexagonExpandCondsets::coalesceSegments(
}
bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
- if (skipFunction(*MF.getFunction()))
+ if (skipFunction(MF.getFunction()))
return false;
HII = static_cast<const HexagonInstrInfo*>(MF.getSubtarget().getInstrInfo());
@@ -1233,7 +1253,7 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
MRI = &MF.getRegInfo();
DEBUG(LIS->print(dbgs() << "Before expand-condsets\n",
- MF.getFunction()->getParent()));
+ MF.getFunction().getParent()));
bool Changed = false;
std::set<unsigned> CoalUpd, PredUpd;
@@ -1261,7 +1281,7 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
KillUpd.insert(Op.getReg());
updateLiveness(KillUpd, false, true, false);
DEBUG(LIS->print(dbgs() << "After coalescing\n",
- MF.getFunction()->getParent()));
+ MF.getFunction().getParent()));
// First, simply split all muxes into a pair of conditional transfers
// and update the live intervals to reflect the new arrangement. The
@@ -1278,7 +1298,7 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
// (because of predicated defs), so make sure they are left untouched.
// Predication does not use live intervals.
DEBUG(LIS->print(dbgs() << "After splitting\n",
- MF.getFunction()->getParent()));
+ MF.getFunction().getParent()));
// Traverse all blocks and collapse predicable instructions feeding
// conditional transfers into predicated instructions.
@@ -1287,7 +1307,7 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
for (auto &B : MF)
Changed |= predicateInBlock(B, PredUpd);
DEBUG(LIS->print(dbgs() << "After predicating\n",
- MF.getFunction()->getParent()));
+ MF.getFunction().getParent()));
PredUpd.insert(CoalUpd.begin(), CoalUpd.end());
updateLiveness(PredUpd, true, true, true);
@@ -1295,7 +1315,7 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
DEBUG({
if (Changed)
LIS->print(dbgs() << "After expand-condsets\n",
- MF.getFunction()->getParent());
+ MF.getFunction().getParent());
});
return Changed;