diff options
Diffstat (limited to 'lib/Target/ARM/Thumb2ITBlockPass.cpp')
-rw-r--r-- | lib/Target/ARM/Thumb2ITBlockPass.cpp | 221 |
1 files changed, 169 insertions, 52 deletions
diff --git a/lib/Target/ARM/Thumb2ITBlockPass.cpp b/lib/Target/ARM/Thumb2ITBlockPass.cpp index e0a5f7f04fa9..3143eb9840ed 100644 --- a/lib/Target/ARM/Thumb2ITBlockPass.cpp +++ b/lib/Target/ARM/Thumb2ITBlockPass.cpp @@ -1,9 +1,8 @@ //===-- Thumb2ITBlockPass.cpp - Insert Thumb-2 IT blocks ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -32,13 +31,16 @@ using namespace llvm; #define DEBUG_TYPE "thumb2-it" +#define PASS_NAME "Thumb IT blocks insertion pass" STATISTIC(NumITs, "Number of IT blocks inserted"); STATISTIC(NumMovedInsts, "Number of predicated instructions moved"); +using RegisterSet = SmallSet<unsigned, 4>; + namespace { - class Thumb2ITBlockPass : public MachineFunctionPass { + class Thumb2ITBlock : public MachineFunctionPass { public: static char ID; @@ -47,7 +49,7 @@ namespace { const TargetRegisterInfo *TRI; ARMFunctionInfo *AFI; - Thumb2ITBlockPass() : MachineFunctionPass(ID) {} + Thumb2ITBlock() : MachineFunctionPass(ID) {} bool runOnMachineFunction(MachineFunction &Fn) override; @@ -57,33 +59,32 @@ namespace { } StringRef getPassName() const override { - return "Thumb IT blocks insertion pass"; + return PASS_NAME; } private: bool MoveCopyOutOfITBlock(MachineInstr *MI, ARMCC::CondCodes CC, ARMCC::CondCodes OCC, - SmallSet<unsigned, 4> &Defs, - SmallSet<unsigned, 4> &Uses); - bool InsertITInstructions(MachineBasicBlock &MBB); + RegisterSet &Defs, RegisterSet &Uses); + bool InsertITInstructions(MachineBasicBlock &Block); }; - char Thumb2ITBlockPass::ID = 0; + char Thumb2ITBlock::ID = 0; } // end anonymous namespace +INITIALIZE_PASS(Thumb2ITBlock, DEBUG_TYPE, PASS_NAME, false, false) + /// TrackDefUses - Tracking what registers are being defined and used by /// instructions in the IT block. This also tracks "dependencies", i.e. uses /// in the IT block that are defined before the IT instruction. -static void TrackDefUses(MachineInstr *MI, - SmallSet<unsigned, 4> &Defs, - SmallSet<unsigned, 4> &Uses, +static void TrackDefUses(MachineInstr *MI, RegisterSet &Defs, RegisterSet &Uses, const TargetRegisterInfo *TRI) { - SmallVector<unsigned, 4> LocalDefs; - SmallVector<unsigned, 4> LocalUses; + using RegList = SmallVector<unsigned, 4>; + RegList LocalDefs; + RegList LocalUses; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); + for (auto &MO : MI->operands()) { if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); @@ -95,27 +96,21 @@ static void TrackDefUses(MachineInstr *MI, LocalDefs.push_back(Reg); } - for (unsigned i = 0, e = LocalUses.size(); i != e; ++i) { - unsigned Reg = LocalUses[i]; - for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true); - Subreg.isValid(); ++Subreg) - Uses.insert(*Subreg); - } + auto InsertUsesDefs = [&](RegList &Regs, RegisterSet &UsesDefs) { + for (unsigned Reg : Regs) + for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true); + Subreg.isValid(); ++Subreg) + UsesDefs.insert(*Subreg); + }; - for (unsigned i = 0, e = LocalDefs.size(); i != e; ++i) { - unsigned Reg = LocalDefs[i]; - for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true); - Subreg.isValid(); ++Subreg) - Defs.insert(*Subreg); - if (Reg == ARM::CPSR) - continue; - } + InsertUsesDefs(LocalDefs, Defs); + InsertUsesDefs(LocalUses, Uses); } /// Clear kill flags for any uses in the given set. This will likely /// conservatively remove more kill flags than are necessary, but removing them /// is safer than incorrect kill flags remaining on instructions. -static void ClearKillFlags(MachineInstr *MI, SmallSet<unsigned, 4> &Uses) { +static void ClearKillFlags(MachineInstr *MI, RegisterSet &Uses) { for (MachineOperand &MO : MI->operands()) { if (!MO.isReg() || MO.isDef() || !MO.isKill()) continue; @@ -138,10 +133,9 @@ static bool isCopy(MachineInstr *MI) { } bool -Thumb2ITBlockPass::MoveCopyOutOfITBlock(MachineInstr *MI, - ARMCC::CondCodes CC, ARMCC::CondCodes OCC, - SmallSet<unsigned, 4> &Defs, - SmallSet<unsigned, 4> &Uses) { +Thumb2ITBlock::MoveCopyOutOfITBlock(MachineInstr *MI, + ARMCC::CondCodes CC, ARMCC::CondCodes OCC, + RegisterSet &Defs, RegisterSet &Uses) { if (!isCopy(MI)) return false; // llvm models select's as two-address instructions. That means a copy @@ -181,10 +175,13 @@ Thumb2ITBlockPass::MoveCopyOutOfITBlock(MachineInstr *MI, // Then peek at the next instruction to see if it's predicated on CC or OCC. // If not, then there is nothing to be gained by moving the copy. - MachineBasicBlock::iterator I = MI; ++I; + MachineBasicBlock::iterator I = MI; + ++I; MachineBasicBlock::iterator E = MI->getParent()->end(); + while (I != E && I->isDebugInstr()) ++I; + if (I != E) { unsigned NPredReg = 0; ARMCC::CondCodes NCC = getITInstrPredicate(*I, NPredReg); @@ -194,12 +191,11 @@ Thumb2ITBlockPass::MoveCopyOutOfITBlock(MachineInstr *MI, return false; } -bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) { +bool Thumb2ITBlock::InsertITInstructions(MachineBasicBlock &MBB) { bool Modified = false; - - SmallSet<unsigned, 4> Defs; - SmallSet<unsigned, 4> Uses; + RegisterSet Defs, Uses; MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); + while (MBBI != E) { MachineInstr *MI = &*MBBI; DebugLoc dl = MI->getDebugLoc(); @@ -246,7 +242,7 @@ bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) { unsigned NPredReg = 0; ARMCC::CondCodes NCC = getITInstrPredicate(*NMI, NPredReg); if (NCC == CC || NCC == OCC) { - Mask |= (NCC & 1) << Pos; + Mask |= ((NCC ^ CC) & 1) << Pos; // Add implicit use of ITSTATE. NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/, true/*isImp*/, false/*isKill*/)); @@ -270,8 +266,6 @@ bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) { // Finalize IT mask. Mask |= (1 << Pos); - // Tag along (firstcond[0] << 4) with the mask. - Mask |= (CC & 1) << 4; MIB.addImm(Mask); // Last instruction in IT block kills ITSTATE. @@ -288,7 +282,7 @@ bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) { return Modified; } -bool Thumb2ITBlockPass::runOnMachineFunction(MachineFunction &Fn) { +bool Thumb2ITBlock::runOnMachineFunction(MachineFunction &Fn) { const ARMSubtarget &STI = static_cast<const ARMSubtarget &>(Fn.getSubtarget()); if (!STI.isThumb2()) @@ -302,11 +296,8 @@ bool Thumb2ITBlockPass::runOnMachineFunction(MachineFunction &Fn) { return false; bool Modified = false; - for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; ) { - MachineBasicBlock &MBB = *MFI; - ++MFI; + for (auto &MBB : Fn ) Modified |= InsertITInstructions(MBB); - } if (Modified) AFI->setHasITBlocks(true); @@ -316,6 +307,132 @@ bool Thumb2ITBlockPass::runOnMachineFunction(MachineFunction &Fn) { /// createThumb2ITBlockPass - Returns an instance of the Thumb2 IT blocks /// insertion pass. -FunctionPass *llvm::createThumb2ITBlockPass() { - return new Thumb2ITBlockPass(); +FunctionPass *llvm::createThumb2ITBlockPass() { return new Thumb2ITBlock(); } + +#undef DEBUG_TYPE +#define DEBUG_TYPE "arm-mve-vpt" + +namespace { + class MVEVPTBlock : public MachineFunctionPass { + public: + static char ID; + const Thumb2InstrInfo *TII; + const TargetRegisterInfo *TRI; + + MVEVPTBlock() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &Fn) override; + + MachineFunctionProperties getRequiredProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::NoVRegs); + } + + StringRef getPassName() const override { + return "MVE VPT block insertion pass"; + } + + private: + bool InsertVPTBlocks(MachineBasicBlock &MBB); + }; + + char MVEVPTBlock::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS(MVEVPTBlock, DEBUG_TYPE, "ARM MVE VPT block pass", false, false) + +enum VPTMaskValue { + T = 8, // 0b1000 + TT = 4, // 0b0100 + TE = 12, // 0b1100 + TTT = 2, // 0b0010 + TTE = 6, // 0b0110 + TEE = 10, // 0b1010 + TET = 14, // 0b1110 + TTTT = 1, // 0b0001 + TTTE = 3, // 0b0011 + TTEE = 5, // 0b0101 + TTET = 7, // 0b0111 + TEEE = 9, // 0b1001 + TEET = 11, // 0b1011 + TETT = 13, // 0b1101 + TETE = 15 // 0b1111 +}; + +bool MVEVPTBlock::InsertVPTBlocks(MachineBasicBlock &Block) { + bool Modified = false; + MachineBasicBlock::iterator MBIter = Block.begin(); + MachineBasicBlock::iterator EndIter = Block.end(); + + while (MBIter != EndIter) { + MachineInstr *MI = &*MBIter; + unsigned PredReg = 0; + DebugLoc dl = MI->getDebugLoc(); + + ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*MI, PredReg); + + // The idea of the predicate is that None, Then and Else are for use when + // handling assembly language: they correspond to the three possible + // suffixes "", "t" and "e" on the mnemonic. So when instructions are read + // from assembly source or disassembled from object code, you expect to see + // a mixture whenever there's a long VPT block. But in code generation, we + // hope we'll never generate an Else as input to this pass. + + assert(Pred != ARMVCC::Else && "VPT block pass does not expect Else preds"); + + if (Pred == ARMVCC::None) { + ++MBIter; + continue; + } + + MachineInstrBuilder MIBuilder = + BuildMI(Block, MBIter, dl, TII->get(ARM::MVE_VPST)); + // The mask value for the VPST instruction is T = 0b1000 = 8 + MIBuilder.addImm(VPTMaskValue::T); + + MachineBasicBlock::iterator VPSTInsertPos = MIBuilder.getInstr(); + int VPTInstCnt = 1; + ARMVCC::VPTCodes NextPred; + + do { + ++MBIter; + NextPred = getVPTInstrPredicate(*MBIter, PredReg); + } while (NextPred != ARMVCC::None && NextPred == Pred && ++VPTInstCnt < 4); + + MachineInstr *LastMI = &*MBIter; + finalizeBundle(Block, VPSTInsertPos.getInstrIterator(), + ++LastMI->getIterator()); + + Modified = true; + LLVM_DEBUG(dbgs() << "VPT block created for: "; MI->dump();); + + ++MBIter; + } + return Modified; +} + +bool MVEVPTBlock::runOnMachineFunction(MachineFunction &Fn) { + const ARMSubtarget &STI = + static_cast<const ARMSubtarget &>(Fn.getSubtarget()); + + if (!STI.isThumb2() || !STI.hasMVEIntegerOps()) + return false; + + TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo()); + TRI = STI.getRegisterInfo(); + + LLVM_DEBUG(dbgs() << "********** ARM MVE VPT BLOCKS **********\n" + << "********** Function: " << Fn.getName() << '\n'); + + bool Modified = false; + for (MachineBasicBlock &MBB : Fn) + Modified |= InsertVPTBlocks(MBB); + + LLVM_DEBUG(dbgs() << "**************************************\n"); + return Modified; } + +/// createMVEVPTBlock - Returns an instance of the MVE VPT block +/// insertion pass. +FunctionPass *llvm::createMVEVPTBlockPass() { return new MVEVPTBlock(); } |