2012-02-18 20:03:15 +08:00
|
|
|
//===-- Thumb2ITBlockPass.cpp - Insert Thumb-2 IT blocks ------------------===//
|
2009-07-10 09:54:42 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2009-07-10 09:54:42 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ARM.h"
|
|
|
|
#include "ARMMachineFunctionInfo.h"
|
2017-01-27 07:40:06 +08:00
|
|
|
#include "ARMSubtarget.h"
|
|
|
|
#include "MCTargetDesc/ARMBaseInfo.h"
|
2009-07-11 15:26:20 +08:00
|
|
|
#include "Thumb2InstrInfo.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
2017-01-27 07:40:06 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2017-01-27 07:40:06 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
2009-07-10 09:54:42 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2011-12-14 10:11:42 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstrBundle.h"
|
2017-01-27 07:40:06 +08:00
|
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
|
|
|
#include "llvm/IR/DebugLoc.h"
|
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
#include <cassert>
|
|
|
|
#include <new>
|
|
|
|
|
2009-07-10 09:54:42 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 10:41:26 +08:00
|
|
|
#define DEBUG_TYPE "thumb2-it"
|
2019-06-18 20:13:11 +08:00
|
|
|
#define PASS_NAME "Thumb IT blocks insertion pass"
|
2014-04-22 10:41:26 +08:00
|
|
|
|
2010-06-09 09:46:50 +08:00
|
|
|
STATISTIC(NumITs, "Number of IT blocks inserted");
|
|
|
|
STATISTIC(NumMovedInsts, "Number of predicated instructions moved");
|
2009-07-10 09:54:42 +08:00
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
using RegisterSet = SmallSet<unsigned, 4>;
|
|
|
|
|
2009-07-10 09:54:42 +08:00
|
|
|
namespace {
|
2017-01-27 07:40:06 +08:00
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
class Thumb2ITBlock : public MachineFunctionPass {
|
2010-06-09 09:46:50 +08:00
|
|
|
public:
|
2009-07-10 09:54:42 +08:00
|
|
|
static char ID;
|
|
|
|
|
2013-11-14 02:29:49 +08:00
|
|
|
bool restrictIT;
|
2009-07-11 15:26:20 +08:00
|
|
|
const Thumb2InstrInfo *TII;
|
2010-06-19 07:09:54 +08:00
|
|
|
const TargetRegisterInfo *TRI;
|
2009-07-10 09:54:42 +08:00
|
|
|
ARMFunctionInfo *AFI;
|
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
Thumb2ITBlock() : MachineFunctionPass(ID) {}
|
2017-01-27 07:40:06 +08:00
|
|
|
|
2014-03-10 10:09:33 +08:00
|
|
|
bool runOnMachineFunction(MachineFunction &Fn) override;
|
2009-07-10 09:54:42 +08:00
|
|
|
|
2016-04-05 01:09:25 +08:00
|
|
|
MachineFunctionProperties getRequiredProperties() const override {
|
|
|
|
return MachineFunctionProperties().set(
|
2016-08-25 09:27:13 +08:00
|
|
|
MachineFunctionProperties::Property::NoVRegs);
|
2016-04-05 01:09:25 +08:00
|
|
|
}
|
|
|
|
|
2016-10-01 10:56:57 +08:00
|
|
|
StringRef getPassName() const override {
|
2019-06-18 20:13:11 +08:00
|
|
|
return PASS_NAME;
|
2009-07-10 09:54:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2010-06-19 07:09:54 +08:00
|
|
|
bool MoveCopyOutOfITBlock(MachineInstr *MI,
|
|
|
|
ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
|
2019-06-18 20:13:11 +08:00
|
|
|
RegisterSet &Defs, RegisterSet &Uses);
|
|
|
|
bool InsertITInstructions(MachineBasicBlock &Block);
|
2009-07-10 09:54:42 +08:00
|
|
|
};
|
2017-01-27 07:40:06 +08:00
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
char Thumb2ITBlock::ID = 0;
|
2017-01-27 07:40:06 +08:00
|
|
|
|
|
|
|
} // end anonymous namespace
|
2009-07-10 09:54:42 +08:00
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
INITIALIZE_PASS(Thumb2ITBlock, DEBUG_TYPE, PASS_NAME, false, false)
|
|
|
|
|
2010-06-19 07:09:54 +08:00
|
|
|
/// 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.
|
2019-06-18 20:13:11 +08:00
|
|
|
static void TrackDefUses(MachineInstr *MI, RegisterSet &Defs, RegisterSet &Uses,
|
2010-06-19 07:09:54 +08:00
|
|
|
const TargetRegisterInfo *TRI) {
|
2019-06-18 20:13:11 +08:00
|
|
|
using RegList = SmallVector<unsigned, 4>;
|
|
|
|
RegList LocalDefs;
|
|
|
|
RegList LocalUses;
|
2010-06-19 07:09:54 +08:00
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
for (auto &MO : MI->operands()) {
|
2010-06-09 09:46:50 +08:00
|
|
|
if (!MO.isReg())
|
|
|
|
continue;
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-16 03:22:08 +08:00
|
|
|
Register Reg = MO.getReg();
|
2010-06-19 07:09:54 +08:00
|
|
|
if (!Reg || Reg == ARM::ITSTATE || Reg == ARM::SP)
|
2010-06-09 09:46:50 +08:00
|
|
|
continue;
|
2010-06-19 07:09:54 +08:00
|
|
|
if (MO.isUse())
|
|
|
|
LocalUses.push_back(Reg);
|
2010-06-09 09:46:50 +08:00
|
|
|
else
|
2010-06-19 07:09:54 +08:00
|
|
|
LocalDefs.push_back(Reg);
|
|
|
|
}
|
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
auto InsertUsesDefs = [&](RegList &Regs, RegisterSet &UsesDefs) {
|
|
|
|
for (unsigned Reg : Regs)
|
|
|
|
for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true);
|
|
|
|
Subreg.isValid(); ++Subreg)
|
|
|
|
UsesDefs.insert(*Subreg);
|
|
|
|
};
|
2010-06-19 07:09:54 +08:00
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
InsertUsesDefs(LocalDefs, Defs);
|
|
|
|
InsertUsesDefs(LocalUses, Uses);
|
2010-06-19 07:09:54 +08:00
|
|
|
}
|
|
|
|
|
[ARM] IT block insertion needs to update kill flags
When forming an IT block from the first MOV here:
%R2<def> = t2MOVr %R0, pred:1, pred:%CPSR, opt:%noreg
%R3<def> = tMOVr %R0<kill>, pred:14, pred:%noreg
the move in to R3 is moved out of the IT block so that later instructions on the same predicate can be inside this block, and we can share the IT instruction.
However, when moving the R3 copy out of the IT block, we need to clear its kill flags for anything in use at this point in time, ie, R0 here.
This appeases the machine verifier which thought that R0 wasn't defined when used.
I have a test case, but its extremely register allocator specific. It would be too fragile to commit a test which depends on the register allocator here.
llvm-svn: 236468
2015-05-05 06:44:47 +08:00
|
|
|
/// 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.
|
2019-06-18 20:13:11 +08:00
|
|
|
static void ClearKillFlags(MachineInstr *MI, RegisterSet &Uses) {
|
2015-05-29 10:56:46 +08:00
|
|
|
for (MachineOperand &MO : MI->operands()) {
|
|
|
|
if (!MO.isReg() || MO.isDef() || !MO.isKill())
|
[ARM] IT block insertion needs to update kill flags
When forming an IT block from the first MOV here:
%R2<def> = t2MOVr %R0, pred:1, pred:%CPSR, opt:%noreg
%R3<def> = tMOVr %R0<kill>, pred:14, pred:%noreg
the move in to R3 is moved out of the IT block so that later instructions on the same predicate can be inside this block, and we can share the IT instruction.
However, when moving the R3 copy out of the IT block, we need to clear its kill flags for anything in use at this point in time, ie, R0 here.
This appeases the machine verifier which thought that R0 wasn't defined when used.
I have a test case, but its extremely register allocator specific. It would be too fragile to commit a test which depends on the register allocator here.
llvm-svn: 236468
2015-05-05 06:44:47 +08:00
|
|
|
continue;
|
2015-05-29 10:56:46 +08:00
|
|
|
if (!Uses.count(MO.getReg()))
|
[ARM] IT block insertion needs to update kill flags
When forming an IT block from the first MOV here:
%R2<def> = t2MOVr %R0, pred:1, pred:%CPSR, opt:%noreg
%R3<def> = tMOVr %R0<kill>, pred:14, pred:%noreg
the move in to R3 is moved out of the IT block so that later instructions on the same predicate can be inside this block, and we can share the IT instruction.
However, when moving the R3 copy out of the IT block, we need to clear its kill flags for anything in use at this point in time, ie, R0 here.
This appeases the machine verifier which thought that R0 wasn't defined when used.
I have a test case, but its extremely register allocator specific. It would be too fragile to commit a test which depends on the register allocator here.
llvm-svn: 236468
2015-05-05 06:44:47 +08:00
|
|
|
continue;
|
2015-05-29 10:56:46 +08:00
|
|
|
MO.setIsKill(false);
|
[ARM] IT block insertion needs to update kill flags
When forming an IT block from the first MOV here:
%R2<def> = t2MOVr %R0, pred:1, pred:%CPSR, opt:%noreg
%R3<def> = tMOVr %R0<kill>, pred:14, pred:%noreg
the move in to R3 is moved out of the IT block so that later instructions on the same predicate can be inside this block, and we can share the IT instruction.
However, when moving the R3 copy out of the IT block, we need to clear its kill flags for anything in use at this point in time, ie, R0 here.
This appeases the machine verifier which thought that R0 wasn't defined when used.
I have a test case, but its extremely register allocator specific. It would be too fragile to commit a test which depends on the register allocator here.
llvm-svn: 236468
2015-05-05 06:44:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-17 06:35:32 +08:00
|
|
|
static bool isCopy(MachineInstr *MI) {
|
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case ARM::MOVr:
|
|
|
|
case ARM::MOVr_TC:
|
|
|
|
case ARM::tMOVr:
|
|
|
|
case ARM::t2MOVr:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-19 07:09:54 +08:00
|
|
|
bool
|
2019-06-18 20:13:11 +08:00
|
|
|
Thumb2ITBlock::MoveCopyOutOfITBlock(MachineInstr *MI,
|
|
|
|
ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
|
|
|
|
RegisterSet &Defs, RegisterSet &Uses) {
|
2010-07-17 06:35:32 +08:00
|
|
|
if (!isCopy(MI))
|
|
|
|
return false;
|
|
|
|
// llvm models select's as two-address instructions. That means a copy
|
|
|
|
// is inserted before a t2MOVccr, etc. If the copy is scheduled in
|
|
|
|
// between selects we would end up creating multiple IT blocks.
|
|
|
|
assert(MI->getOperand(0).getSubReg() == 0 &&
|
|
|
|
MI->getOperand(1).getSubReg() == 0 &&
|
|
|
|
"Sub-register indices still around?");
|
|
|
|
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-16 03:22:08 +08:00
|
|
|
Register DstReg = MI->getOperand(0).getReg();
|
|
|
|
Register SrcReg = MI->getOperand(1).getReg();
|
2010-07-17 06:35:32 +08:00
|
|
|
|
|
|
|
// First check if it's safe to move it.
|
|
|
|
if (Uses.count(DstReg) || Defs.count(SrcReg))
|
|
|
|
return false;
|
|
|
|
|
If the CPSR is defined by a copy, then we don't want to merge it into an IT
block. E.g., if we have:
movs r1, r1
rsb r1, 0
movs r2, r2
rsb r2, 0
we don't want this to be converted to:
movs r1, r1
movs r2, r2
itt mi
rsb r1, 0
rsb r2, 0
PR11107 & <rdar://problem/10259534>
llvm-svn: 141589
2011-10-11 06:52:53 +08:00
|
|
|
// If the CPSR is defined by this copy, then we don't want to move it. E.g.,
|
|
|
|
// if we have:
|
|
|
|
//
|
|
|
|
// movs r1, r1
|
|
|
|
// rsb r1, 0
|
|
|
|
// movs r2, r2
|
|
|
|
// rsb r2, 0
|
|
|
|
//
|
|
|
|
// we don't want this to be converted to:
|
|
|
|
//
|
|
|
|
// movs r1, r1
|
|
|
|
// movs r2, r2
|
|
|
|
// itt mi
|
|
|
|
// rsb r1, 0
|
|
|
|
// rsb r2, 0
|
|
|
|
//
|
2011-10-11 08:10:41 +08:00
|
|
|
const MCInstrDesc &MCID = MI->getDesc();
|
2011-12-07 15:15:52 +08:00
|
|
|
if (MI->hasOptionalDef() &&
|
2011-10-11 08:10:41 +08:00
|
|
|
MI->getOperand(MCID.getNumOperands() - 1).getReg() == ARM::CPSR)
|
|
|
|
return false;
|
If the CPSR is defined by a copy, then we don't want to merge it into an IT
block. E.g., if we have:
movs r1, r1
rsb r1, 0
movs r2, r2
rsb r2, 0
we don't want this to be converted to:
movs r1, r1
movs r2, r2
itt mi
rsb r1, 0
rsb r2, 0
PR11107 & <rdar://problem/10259534>
llvm-svn: 141589
2011-10-11 06:52:53 +08:00
|
|
|
|
2010-07-17 06:35:32 +08:00
|
|
|
// 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.
|
2019-06-18 20:13:11 +08:00
|
|
|
MachineBasicBlock::iterator I = MI;
|
|
|
|
++I;
|
2010-07-17 06:35:32 +08:00
|
|
|
MachineBasicBlock::iterator E = MI->getParent()->end();
|
2019-06-18 20:13:11 +08:00
|
|
|
|
2018-05-09 10:42:00 +08:00
|
|
|
while (I != E && I->isDebugInstr())
|
2010-07-17 06:35:32 +08:00
|
|
|
++I;
|
2019-06-18 20:13:11 +08:00
|
|
|
|
2010-07-17 06:35:32 +08:00
|
|
|
if (I != E) {
|
2020-04-08 05:28:53 +08:00
|
|
|
Register NPredReg;
|
2016-02-23 10:46:52 +08:00
|
|
|
ARMCC::CondCodes NCC = getITInstrPredicate(*I, NPredReg);
|
2010-07-17 06:35:32 +08:00
|
|
|
if (NCC == CC || NCC == OCC)
|
|
|
|
return true;
|
2010-06-09 09:46:50 +08:00
|
|
|
}
|
2010-06-19 07:09:54 +08:00
|
|
|
return false;
|
2010-06-09 09:46:50 +08:00
|
|
|
}
|
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
bool Thumb2ITBlock::InsertITInstructions(MachineBasicBlock &MBB) {
|
2009-07-10 09:54:42 +08:00
|
|
|
bool Modified = false;
|
2019-06-18 20:13:11 +08:00
|
|
|
RegisterSet Defs, Uses;
|
2009-07-10 09:54:42 +08:00
|
|
|
MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
|
2019-06-18 20:13:11 +08:00
|
|
|
|
2009-07-10 09:54:42 +08:00
|
|
|
while (MBBI != E) {
|
|
|
|
MachineInstr *MI = &*MBBI;
|
2009-09-28 17:14:39 +08:00
|
|
|
DebugLoc dl = MI->getDebugLoc();
|
2020-04-08 05:28:53 +08:00
|
|
|
Register PredReg;
|
2016-02-23 10:46:52 +08:00
|
|
|
ARMCC::CondCodes CC = getITInstrPredicate(*MI, PredReg);
|
2009-07-10 09:54:42 +08:00
|
|
|
if (CC == ARMCC::AL) {
|
|
|
|
++MBBI;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-06-09 09:46:50 +08:00
|
|
|
Defs.clear();
|
|
|
|
Uses.clear();
|
2010-06-19 07:09:54 +08:00
|
|
|
TrackDefUses(MI, Defs, Uses, TRI);
|
2010-06-09 09:46:50 +08:00
|
|
|
|
2009-07-10 09:54:42 +08:00
|
|
|
// Insert an IT instruction.
|
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(ARM::t2IT))
|
|
|
|
.addImm(CC);
|
2010-06-19 07:09:54 +08:00
|
|
|
|
|
|
|
// Add implicit use of ITSTATE to IT block instructions.
|
|
|
|
MI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/,
|
|
|
|
true/*isImp*/, false/*isKill*/));
|
|
|
|
|
|
|
|
MachineInstr *LastITMI = MI;
|
2014-11-01 07:19:46 +08:00
|
|
|
MachineBasicBlock::iterator InsertPos = MIB.getInstr();
|
2009-07-10 09:54:42 +08:00
|
|
|
++MBBI;
|
|
|
|
|
2010-06-19 07:09:54 +08:00
|
|
|
// Form IT block.
|
2009-07-10 09:54:42 +08:00
|
|
|
ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC);
|
2009-08-15 15:59:10 +08:00
|
|
|
unsigned Mask = 0, Pos = 3;
|
2013-09-09 22:21:49 +08:00
|
|
|
|
2013-11-14 02:29:49 +08:00
|
|
|
// v8 IT blocks are limited to one conditional op unless -arm-no-restrict-it
|
|
|
|
// is set: skip the loop
|
|
|
|
if (!restrictIT) {
|
2013-09-09 22:21:49 +08:00
|
|
|
// Branches, including tricky ones like LDM_RET, need to end an IT
|
|
|
|
// block so check the instruction we just put in the block.
|
|
|
|
for (; MBBI != E && Pos &&
|
|
|
|
(!MI->isBranch() && !MI->isReturn()) ; ++MBBI) {
|
2018-05-09 10:42:00 +08:00
|
|
|
if (MBBI->isDebugInstr())
|
2010-06-19 07:09:54 +08:00
|
|
|
continue;
|
2013-09-09 22:21:49 +08:00
|
|
|
|
|
|
|
MachineInstr *NMI = &*MBBI;
|
|
|
|
MI = NMI;
|
|
|
|
|
2020-04-08 05:28:53 +08:00
|
|
|
Register NPredReg;
|
2016-02-23 10:46:52 +08:00
|
|
|
ARMCC::CondCodes NCC = getITInstrPredicate(*NMI, NPredReg);
|
2013-09-09 22:21:49 +08:00
|
|
|
if (NCC == CC || NCC == OCC) {
|
[ARM] Refactor handling of IT mask operands.
During assembly, the mask operand to an IT instruction (storing the
sequence of T/E for 'Then' and 'Else') is parsed out of the mnemonic
into a representation that encodes 'Then' and 'Else' in the same way
regardless of the condition code. At some point during encoding it has
to be converted into the instruction encoding used in the
architecture, in which the mask encodes a sequence of replacement
low-order bits for the condition code, so that which bit value means
'then' and which 'else' depends on whether the original condition code
had its low bit set.
Previously, that transformation was done by processInstruction(), half
way through assembly. So an MCOperand storing an IT mask would
sometimes store it in one format, and sometimes in the other,
depending on where in the assembly pipeline you were. You can see this
in diagnostics from `llvm-mc -debug -triple=thumbv8a -show-inst`, for
example: if you give it an instruction such as `itete eq`, you'd see
an `<MCOperand Imm:5>` in a diagnostic become `<MCOperand Imm:11>` in
the final output.
Having the same data structure store values with time-dependent
semantics is confusing already, and it will get more confusing when we
introduce the MVE VPT instruction which reuses the Then/Else bitmask
idea in a different context. So I'm refactoring: now, all `ARMOperand`
and `MCOperand` representations of an IT mask work exactly the same
way, namely, 0 means 'Then' and 1 means 'Else', regardless of what
original predicate is being referred to. The architectural encoding of
IT that depends on the original condition is now constructed at the
point when we turn the `MCOperand` into the final instruction bit
pattern, and decoded similarly in the disassembler.
The previous condition-independent parse-time format used 0 for Else
and 1 for Then. I've taken the opportunity to flip the sense of it
while I'm changing all of this anyway, because it seems to me more
natural to use 0 for 'leave the starting condition unchanged' and 1
for 'invert it', as if those bits were an XOR mask.
Reviewers: ostannard
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63219
llvm-svn: 363244
2019-06-13 18:01:52 +08:00
|
|
|
Mask |= ((NCC ^ CC) & 1) << Pos;
|
2013-09-09 22:21:49 +08:00
|
|
|
// Add implicit use of ITSTATE.
|
|
|
|
NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/,
|
|
|
|
true/*isImp*/, false/*isKill*/));
|
|
|
|
LastITMI = NMI;
|
|
|
|
} else {
|
|
|
|
if (NCC == ARMCC::AL &&
|
|
|
|
MoveCopyOutOfITBlock(NMI, CC, OCC, Defs, Uses)) {
|
|
|
|
--MBBI;
|
|
|
|
MBB.remove(NMI);
|
|
|
|
MBB.insert(InsertPos, NMI);
|
[ARM] IT block insertion needs to update kill flags
When forming an IT block from the first MOV here:
%R2<def> = t2MOVr %R0, pred:1, pred:%CPSR, opt:%noreg
%R3<def> = tMOVr %R0<kill>, pred:14, pred:%noreg
the move in to R3 is moved out of the IT block so that later instructions on the same predicate can be inside this block, and we can share the IT instruction.
However, when moving the R3 copy out of the IT block, we need to clear its kill flags for anything in use at this point in time, ie, R0 here.
This appeases the machine verifier which thought that R0 wasn't defined when used.
I have a test case, but its extremely register allocator specific. It would be too fragile to commit a test which depends on the register allocator here.
llvm-svn: 236468
2015-05-05 06:44:47 +08:00
|
|
|
ClearKillFlags(MI, Uses);
|
2013-09-09 22:21:49 +08:00
|
|
|
++NumMovedInsts;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
2010-06-09 09:46:50 +08:00
|
|
|
}
|
2013-09-09 22:21:49 +08:00
|
|
|
TrackDefUses(NMI, Defs, Uses, TRI);
|
|
|
|
--Pos;
|
2010-06-09 09:46:50 +08:00
|
|
|
}
|
2009-07-10 09:54:42 +08:00
|
|
|
}
|
2010-06-09 09:46:50 +08:00
|
|
|
|
2010-06-19 07:09:54 +08:00
|
|
|
// Finalize IT mask.
|
2009-08-15 15:59:10 +08:00
|
|
|
Mask |= (1 << Pos);
|
2009-07-10 09:54:42 +08:00
|
|
|
MIB.addImm(Mask);
|
2010-06-19 07:09:54 +08:00
|
|
|
|
|
|
|
// Last instruction in IT block kills ITSTATE.
|
|
|
|
LastITMI->findRegisterUseOperand(ARM::ITSTATE)->setIsKill();
|
|
|
|
|
2011-12-14 10:11:42 +08:00
|
|
|
// Finalize the bundle.
|
2016-02-23 05:30:15 +08:00
|
|
|
finalizeBundle(MBB, InsertPos.getInstrIterator(),
|
|
|
|
++LastITMI->getIterator());
|
2011-12-14 10:11:42 +08:00
|
|
|
|
2009-07-10 09:54:42 +08:00
|
|
|
Modified = true;
|
|
|
|
++NumITs;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Modified;
|
|
|
|
}
|
|
|
|
|
2019-06-18 20:13:11 +08:00
|
|
|
bool Thumb2ITBlock::runOnMachineFunction(MachineFunction &Fn) {
|
2015-01-29 08:19:33 +08:00
|
|
|
const ARMSubtarget &STI =
|
|
|
|
static_cast<const ARMSubtarget &>(Fn.getSubtarget());
|
2015-03-05 08:23:40 +08:00
|
|
|
if (!STI.isThumb2())
|
|
|
|
return false;
|
2009-07-10 09:54:42 +08:00
|
|
|
AFI = Fn.getInfo<ARMFunctionInfo>();
|
2015-01-29 08:19:33 +08:00
|
|
|
TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo());
|
|
|
|
TRI = STI.getRegisterInfo();
|
|
|
|
restrictIT = STI.restrictIT();
|
2009-07-10 09:54:42 +08:00
|
|
|
|
|
|
|
if (!AFI->isThumbFunction())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool Modified = false;
|
2019-06-18 20:13:11 +08:00
|
|
|
for (auto &MBB : Fn )
|
2010-07-03 05:07:09 +08:00
|
|
|
Modified |= InsertITInstructions(MBB);
|
2009-07-10 09:54:42 +08:00
|
|
|
|
2010-07-03 05:07:09 +08:00
|
|
|
if (Modified)
|
2010-06-19 07:09:54 +08:00
|
|
|
AFI->setHasITBlocks(true);
|
|
|
|
|
2009-07-10 09:54:42 +08:00
|
|
|
return Modified;
|
|
|
|
}
|
|
|
|
|
2009-08-08 10:54:37 +08:00
|
|
|
/// createThumb2ITBlockPass - Returns an instance of the Thumb2 IT blocks
|
2009-07-10 09:54:42 +08:00
|
|
|
/// insertion pass.
|
2019-06-18 20:13:11 +08:00
|
|
|
FunctionPass *llvm::createThumb2ITBlockPass() { return new Thumb2ITBlock(); }
|