1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00

[globalisel][tablegen] Compute available feature bits correctly.

Summary:
Predicate<> now has a field to indicate how often it must be recomputed.
Currently, there are two frequencies, per-module (RecomputePerFunction==0)
and per-function (RecomputePerFunction==1). Per-function predicates are
currently recomputed more frequently than necessary since the only predicate
in this category is cheap to test. Per-module predicates are now computed in
getSubtargetImpl() while per-function predicates are computed in selectImpl().

Tablegen now manages the PredicateBitset internally. It should only be
necessary to add the required includes.

Also fixed a problem revealed by the test case where
constrainSelectedInstRegOperands() would attempt to tie operands that
BuildMI had already tied.

Reviewers: ab, qcolombet, t.p.northover, rovka, aditya_nandakumar

Reviewed By: rovka

Subscribers: kristof.beyls, igorb, llvm-commits

Differential Revision: https://reviews.llvm.org/D32491

llvm-svn: 301750
This commit is contained in:
Daniel Sanders 2017-04-29 17:30:09 +00:00
parent 4493f8350b
commit 6ad3513c78
19 changed files with 209 additions and 100 deletions

View File

@ -61,9 +61,6 @@ class InstructionSelector {
public: public:
virtual ~InstructionSelector() {} virtual ~InstructionSelector() {}
/// This is executed before selecting a function.
virtual void beginFunction(const MachineFunction &MF) {}
/// Select the (possibly generic) instruction \p I to only use target-specific /// Select the (possibly generic) instruction \p I to only use target-specific
/// opcodes. It is OK to insert multiple instructions, but they cannot be /// opcodes. It is OK to insert multiple instructions, but they cannot be
/// generic pre-isel instructions. /// generic pre-isel instructions.

View File

@ -530,6 +530,12 @@ class Predicate<string cond> {
/// PredicateName - User-level name to use for the predicate. Mainly for use /// PredicateName - User-level name to use for the predicate. Mainly for use
/// in diagnostics such as missing feature errors in the asm matcher. /// in diagnostics such as missing feature errors in the asm matcher.
string PredicateName = ""; string PredicateName = "";
/// Setting this to '1' indicates that the predicate must be recomputed on
/// every function change. Most predicates can leave this at '0'.
///
/// Ignored by SelectionDAG, it always recomputes the predicate on every use.
bit RecomputePerFunction = 0;
} }
/// NoHonorSignDependentRounding - This predicate is true if support for /// NoHonorSignDependentRounding - This predicate is true if support for

View File

@ -58,10 +58,11 @@ bool InstructionSelector::constrainSelectedInstRegOperands(
MO.setReg(constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, I.getDesc(), MO.setReg(constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, I.getDesc(),
Reg, OpI)); Reg, OpI));
// Tie uses to defs as indicated in MCInstrDesc. // Tie uses to defs as indicated in MCInstrDesc if this hasn't already been
// done.
if (MO.isUse()) { if (MO.isUse()) {
int DefIdx = I.getDesc().getOperandConstraint(OpI, MCOI::TIED_TO); int DefIdx = I.getDesc().getOperandConstraint(OpI, MCOI::TIED_TO);
if (DefIdx != -1) if (DefIdx != -1 && !I.isRegTiedToUseOperand(DefIdx))
I.tieOperands(DefIdx, OpI); I.tieOperands(DefIdx, OpI);
} }
} }

View File

@ -314,8 +314,8 @@ def AArch64umaxv : SDNode<"AArch64ISD::UMAXV", SDT_AArch64UnaryVec>;
// AArch64 Instruction Predicate Definitions. // AArch64 Instruction Predicate Definitions.
def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">; def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">;
def IsNotDarwin: Predicate<"!Subtarget->isTargetDarwin()">; def IsNotDarwin: Predicate<"!Subtarget->isTargetDarwin()">;
def ForCodeSize : Predicate<"ForCodeSize">; def ForCodeSize : Predicate<"Subtarget->getForCodeSize()">;
def NotForCodeSize : Predicate<"!ForCodeSize">; def NotForCodeSize : Predicate<"!Subtarget->getForCodeSize()">;
include "AArch64InstrFormats.td" include "AArch64InstrFormats.td"

View File

@ -51,7 +51,6 @@ public:
const AArch64Subtarget &STI, const AArch64Subtarget &STI,
const AArch64RegisterBankInfo &RBI); const AArch64RegisterBankInfo &RBI);
void beginFunction(const MachineFunction &MF) override;
bool select(MachineInstr &I) const override; bool select(MachineInstr &I) const override;
private: private:
@ -74,12 +73,10 @@ private:
const AArch64InstrInfo &TII; const AArch64InstrInfo &TII;
const AArch64RegisterInfo &TRI; const AArch64RegisterInfo &TRI;
const AArch64RegisterBankInfo &RBI; const AArch64RegisterBankInfo &RBI;
bool ForCodeSize;
PredicateBitset AvailableFeatures; #define GET_GLOBALISEL_PREDICATES_DECL
PredicateBitset #include "AArch64GenGlobalISel.inc"
computeAvailableFeatures(const MachineFunction *MF, #undef GET_GLOBALISEL_PREDICATES_DECL
const AArch64Subtarget *Subtarget) const;
// We declare the temporaries used by selectImpl() in the class to minimize the // We declare the temporaries used by selectImpl() in the class to minimize the
// cost of constructing placeholder values. // cost of constructing placeholder values.
@ -98,7 +95,10 @@ AArch64InstructionSelector::AArch64InstructionSelector(
const AArch64TargetMachine &TM, const AArch64Subtarget &STI, const AArch64TargetMachine &TM, const AArch64Subtarget &STI,
const AArch64RegisterBankInfo &RBI) const AArch64RegisterBankInfo &RBI)
: InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()), RBI(RBI), ForCodeSize(), AvailableFeatures() TRI(*STI.getRegisterInfo()), RBI(RBI),
#define GET_GLOBALISEL_PREDICATES_INIT
#include "AArch64GenGlobalISel.inc"
#undef GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT #define GET_GLOBALISEL_TEMPORARIES_INIT
#include "AArch64GenGlobalISel.inc" #include "AArch64GenGlobalISel.inc"
#undef GET_GLOBALISEL_TEMPORARIES_INIT #undef GET_GLOBALISEL_TEMPORARIES_INIT
@ -577,12 +577,6 @@ bool AArch64InstructionSelector::selectVaStartDarwin(
return true; return true;
} }
void AArch64InstructionSelector::beginFunction(
const MachineFunction &MF) {
ForCodeSize = MF.getFunction()->optForSize();
AvailableFeatures = computeAvailableFeatures(&MF, &STI);
}
bool AArch64InstructionSelector::select(MachineInstr &I) const { bool AArch64InstructionSelector::select(MachineInstr &I) const {
assert(I.getParent() && "Instruction should be in a basic block!"); assert(I.getParent() && "Instruction should be in a basic block!");
assert(I.getParent()->getParent() && "Instruction should be in a function!"); assert(I.getParent()->getParent() && "Instruction should be in a function!");

View File

@ -113,11 +113,12 @@ void AArch64Subtarget::initializeProperties() {
AArch64Subtarget::AArch64Subtarget(const Triple &TT, const std::string &CPU, AArch64Subtarget::AArch64Subtarget(const Triple &TT, const std::string &CPU,
const std::string &FS, const std::string &FS,
const TargetMachine &TM, bool LittleEndian) const TargetMachine &TM, bool LittleEndian,
bool ForCodeSize)
: AArch64GenSubtargetInfo(TT, CPU, FS), ReserveX18(TT.isOSDarwin()), : AArch64GenSubtargetInfo(TT, CPU, FS), ReserveX18(TT.isOSDarwin()),
IsLittle(LittleEndian), TargetTriple(TT), FrameLowering(), IsLittle(LittleEndian), TargetTriple(TT), FrameLowering(),
InstrInfo(initializeSubtargetDependencies(FS, CPU)), TSInfo(), InstrInfo(initializeSubtargetDependencies(FS, CPU)), TSInfo(),
TLInfo(TM, *this), GISel() {} TLInfo(TM, *this), GISel(), ForCodeSize(ForCodeSize) {}
const CallLowering *AArch64Subtarget::getCallLowering() const { const CallLowering *AArch64Subtarget::getCallLowering() const {
assert(GISel && "Access to GlobalISel APIs not set"); assert(GISel && "Access to GlobalISel APIs not set");

View File

@ -124,6 +124,8 @@ protected:
/// an optional library. /// an optional library.
std::unique_ptr<GISelAccessor> GISel; std::unique_ptr<GISelAccessor> GISel;
bool ForCodeSize;
private: private:
/// initializeSubtargetDependencies - Initializes using CPUString and the /// initializeSubtargetDependencies - Initializes using CPUString and the
/// passed in feature string so that we can use initializer lists for /// passed in feature string so that we can use initializer lists for
@ -139,7 +141,7 @@ public:
/// of the specified triple. /// of the specified triple.
AArch64Subtarget(const Triple &TT, const std::string &CPU, AArch64Subtarget(const Triple &TT, const std::string &CPU,
const std::string &FS, const TargetMachine &TM, const std::string &FS, const TargetMachine &TM,
bool LittleEndian); bool LittleEndian, bool ForCodeSize);
/// This object will take onwership of \p GISelAccessor. /// This object will take onwership of \p GISelAccessor.
void setGISelAccessor(GISelAccessor &GISel) { void setGISelAccessor(GISelAccessor &GISel) {
@ -262,6 +264,8 @@ public:
} }
} }
bool getForCodeSize() const { return ForCodeSize; }
/// ParseSubtargetFeatures - Parses features string setting specified /// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen. /// subtarget options. Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS); void ParseSubtargetFeatures(StringRef CPU, StringRef FS);

View File

@ -255,6 +255,7 @@ const AArch64Subtarget *
AArch64TargetMachine::getSubtargetImpl(const Function &F) const { AArch64TargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu"); Attribute CPUAttr = F.getFnAttribute("target-cpu");
Attribute FSAttr = F.getFnAttribute("target-features"); Attribute FSAttr = F.getFnAttribute("target-features");
bool ForCodeSize = F.optForSize();
std::string CPU = !CPUAttr.hasAttribute(Attribute::None) std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
? CPUAttr.getValueAsString().str() ? CPUAttr.getValueAsString().str()
@ -262,15 +263,17 @@ AArch64TargetMachine::getSubtargetImpl(const Function &F) const {
std::string FS = !FSAttr.hasAttribute(Attribute::None) std::string FS = !FSAttr.hasAttribute(Attribute::None)
? FSAttr.getValueAsString().str() ? FSAttr.getValueAsString().str()
: TargetFS; : TargetFS;
std::string ForCodeSizeStr =
std::string(ForCodeSize ? "+" : "-") + "forcodesize";
auto &I = SubtargetMap[CPU + FS]; auto &I = SubtargetMap[CPU + FS + ForCodeSizeStr];
if (!I) { if (!I) {
// This needs to be done before we create a new subtarget since any // This needs to be done before we create a new subtarget since any
// creation will depend on the TM and the code generation flags on the // creation will depend on the TM and the code generation flags on the
// function that reside in TargetOptions. // function that reside in TargetOptions.
resetTargetOptions(F); resetTargetOptions(F);
I = llvm::make_unique<AArch64Subtarget>(TargetTriple, CPU, FS, *this, I = llvm::make_unique<AArch64Subtarget>(TargetTriple, CPU, FS, *this,
isLittle); isLittle, ForCodeSize);
#ifndef LLVM_BUILD_GLOBAL_ISEL #ifndef LLVM_BUILD_GLOBAL_ISEL
GISelAccessor *GISel = new GISelAccessor(); GISelAccessor *GISel = new GISelAccessor();
#else #else

View File

@ -877,7 +877,9 @@ def In32BitMode : Predicate<"Subtarget->is32Bit()">,
def IsWin64 : Predicate<"Subtarget->isTargetWin64()">; def IsWin64 : Predicate<"Subtarget->isTargetWin64()">;
def NotWin64 : Predicate<"!Subtarget->isTargetWin64()">; def NotWin64 : Predicate<"!Subtarget->isTargetWin64()">;
def NotWin64WithoutFP : Predicate<"!Subtarget->isTargetWin64() ||" def NotWin64WithoutFP : Predicate<"!Subtarget->isTargetWin64() ||"
"Subtarget->getFrameLowering()->hasFP(*MF)">; "Subtarget->getFrameLowering()->hasFP(*MF)"> {
let RecomputePerFunction = 1;
}
def IsPS4 : Predicate<"Subtarget->isTargetPS4()">; def IsPS4 : Predicate<"Subtarget->isTargetPS4()">;
def NotPS4 : Predicate<"!Subtarget->isTargetPS4()">; def NotPS4 : Predicate<"!Subtarget->isTargetPS4()">;
def IsNaCl : Predicate<"Subtarget->isTargetNaCl()">; def IsNaCl : Predicate<"Subtarget->isTargetNaCl()">;
@ -887,9 +889,9 @@ def KernelCode : Predicate<"TM.getCodeModel() == CodeModel::Kernel">;
def NearData : Predicate<"TM.getCodeModel() == CodeModel::Small ||" def NearData : Predicate<"TM.getCodeModel() == CodeModel::Small ||"
"TM.getCodeModel() == CodeModel::Kernel">; "TM.getCodeModel() == CodeModel::Kernel">;
def IsNotPIC : Predicate<"!TM.isPositionIndependent()">; def IsNotPIC : Predicate<"!TM.isPositionIndependent()">;
def OptForSize : Predicate<"OptForSize">; def OptForSize : Predicate<"Subtarget->getOptForSize()">;
def OptForMinSize : Predicate<"OptForMinSize">; def OptForMinSize : Predicate<"Subtarget->getOptForMinSize()">;
def OptForSpeed : Predicate<"!OptForSize">; def OptForSpeed : Predicate<"!Subtarget->getOptForSize()">;
def FastBTMem : Predicate<"!Subtarget->isBTMemSlow()">; def FastBTMem : Predicate<"!Subtarget->isBTMemSlow()">;
def CallImmAddr : Predicate<"Subtarget->isLegalToCallImmediateAddr()">; def CallImmAddr : Predicate<"Subtarget->isLegalToCallImmediateAddr()">;
def FavorMemIndirectCall : Predicate<"!Subtarget->callRegIndirect()">; def FavorMemIndirectCall : Predicate<"!Subtarget->callRegIndirect()">;

View File

@ -48,7 +48,6 @@ public:
X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI, X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI,
const X86RegisterBankInfo &RBI); const X86RegisterBankInfo &RBI);
void beginFunction(const MachineFunction &MF) override;
bool select(MachineInstr &I) const override; bool select(MachineInstr &I) const override;
private: private:
@ -80,12 +79,10 @@ private:
const X86InstrInfo &TII; const X86InstrInfo &TII;
const X86RegisterInfo &TRI; const X86RegisterInfo &TRI;
const X86RegisterBankInfo &RBI; const X86RegisterBankInfo &RBI;
bool OptForSize;
bool OptForMinSize;
PredicateBitset AvailableFeatures; #define GET_GLOBALISEL_PREDICATES_DECL
PredicateBitset computeAvailableFeatures(const MachineFunction *MF, #include "X86GenGlobalISel.inc"
const X86Subtarget *Subtarget) const; #undef GET_GLOBALISEL_PREDICATES_DECL
#define GET_GLOBALISEL_TEMPORARIES_DECL #define GET_GLOBALISEL_TEMPORARIES_DECL
#include "X86GenGlobalISel.inc" #include "X86GenGlobalISel.inc"
@ -102,8 +99,10 @@ X86InstructionSelector::X86InstructionSelector(const X86TargetMachine &TM,
const X86Subtarget &STI, const X86Subtarget &STI,
const X86RegisterBankInfo &RBI) const X86RegisterBankInfo &RBI)
: InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()), RBI(RBI), OptForSize(false), TRI(*STI.getRegisterInfo()), RBI(RBI),
OptForMinSize(false), AvailableFeatures() #define GET_GLOBALISEL_PREDICATES_INIT
#include "X86GenGlobalISel.inc"
#undef GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT #define GET_GLOBALISEL_TEMPORARIES_INIT
#include "X86GenGlobalISel.inc" #include "X86GenGlobalISel.inc"
#undef GET_GLOBALISEL_TEMPORARIES_INIT #undef GET_GLOBALISEL_TEMPORARIES_INIT
@ -206,12 +205,6 @@ static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
return true; return true;
} }
void X86InstructionSelector::beginFunction(const MachineFunction &MF) {
OptForSize = MF.getFunction()->optForSize();
OptForMinSize = MF.getFunction()->optForMinSize();
AvailableFeatures = computeAvailableFeatures(&MF, &STI);
}
bool X86InstructionSelector::select(MachineInstr &I) const { bool X86InstructionSelector::select(MachineInstr &I) const {
assert(I.getParent() && "Instruction should be in a basic block!"); assert(I.getParent() && "Instruction should be in a basic block!");
assert(I.getParent()->getParent() && "Instruction should be in a function!"); assert(I.getParent()->getParent() && "Instruction should be in a function!");

View File

@ -326,7 +326,8 @@ X86Subtarget &X86Subtarget::initializeSubtargetDependencies(StringRef CPU,
X86Subtarget::X86Subtarget(const Triple &TT, StringRef CPU, StringRef FS, X86Subtarget::X86Subtarget(const Triple &TT, StringRef CPU, StringRef FS,
const X86TargetMachine &TM, const X86TargetMachine &TM,
unsigned StackAlignOverride) unsigned StackAlignOverride, bool OptForSize,
bool OptForMinSize)
: X86GenSubtargetInfo(TT, CPU, FS), X86ProcFamily(Others), : X86GenSubtargetInfo(TT, CPU, FS), X86ProcFamily(Others),
PICStyle(PICStyles::None), TM(TM), TargetTriple(TT), PICStyle(PICStyles::None), TM(TM), TargetTriple(TT),
StackAlignOverride(StackAlignOverride), StackAlignOverride(StackAlignOverride),
@ -335,8 +336,9 @@ X86Subtarget::X86Subtarget(const Triple &TT, StringRef CPU, StringRef FS,
TargetTriple.getEnvironment() != Triple::CODE16), TargetTriple.getEnvironment() != Triple::CODE16),
In16BitMode(TargetTriple.getArch() == Triple::x86 && In16BitMode(TargetTriple.getArch() == Triple::x86 &&
TargetTriple.getEnvironment() == Triple::CODE16), TargetTriple.getEnvironment() == Triple::CODE16),
InstrInfo(initializeSubtargetDependencies(CPU, FS)), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this),
TLInfo(TM, *this), FrameLowering(*this, getStackAlignment()) { FrameLowering(*this, getStackAlignment()), OptForSize(OptForSize),
OptForMinSize(OptForMinSize) {
// Determine the PICStyle based on the target selected. // Determine the PICStyle based on the target selected.
if (!isPositionIndependent()) if (!isPositionIndependent())
setPICStyle(PICStyles::None); setPICStyle(PICStyles::None);

View File

@ -328,12 +328,16 @@ private:
X86TargetLowering TLInfo; X86TargetLowering TLInfo;
X86FrameLowering FrameLowering; X86FrameLowering FrameLowering;
bool OptForSize;
bool OptForMinSize;
public: public:
/// This constructor initializes the data members to match that /// This constructor initializes the data members to match that
/// of the specified triple. /// of the specified triple.
/// ///
X86Subtarget(const Triple &TT, StringRef CPU, StringRef FS, X86Subtarget(const Triple &TT, StringRef CPU, StringRef FS,
const X86TargetMachine &TM, unsigned StackAlignOverride); const X86TargetMachine &TM, unsigned StackAlignOverride,
bool OptForSize, bool OptForMinSize);
/// This object will take onwership of \p GISelAccessor. /// This object will take onwership of \p GISelAccessor.
void setGISelAccessor(GISelAccessor &GISel) { this->GISel.reset(&GISel); } void setGISelAccessor(GISelAccessor &GISel) { this->GISel.reset(&GISel); }
@ -499,6 +503,9 @@ public:
bool isSLM() const { return X86ProcFamily == IntelSLM; } bool isSLM() const { return X86ProcFamily == IntelSLM; }
bool useSoftFloat() const { return UseSoftFloat; } bool useSoftFloat() const { return UseSoftFloat; }
bool getOptForSize() const { return OptForSize; }
bool getOptForMinSize() const { return OptForMinSize; }
/// Use mfence if we have SSE2 or we're on x86-64 (even if we asked for /// Use mfence if we have SSE2 or we're on x86-64 (even if we asked for
/// no-sse2). There isn't any reason to disable it if the target processor /// no-sse2). There isn't any reason to disable it if the target processor
/// supports it. /// supports it.

View File

@ -268,6 +268,12 @@ X86TargetMachine::getSubtargetImpl(const Function &F) const {
FS = Key.substr(CPU.size()); FS = Key.substr(CPU.size());
bool OptForSize = F.optForSize();
bool OptForMinSize = F.optForMinSize();
Key += std::string(OptForSize ? "+" : "-") + "optforsize";
Key += std::string(OptForMinSize ? "+" : "-") + "optforminsize";
auto &I = SubtargetMap[Key]; auto &I = SubtargetMap[Key];
if (!I) { if (!I) {
// This needs to be done before we create a new subtarget since any // This needs to be done before we create a new subtarget since any
@ -275,7 +281,8 @@ X86TargetMachine::getSubtargetImpl(const Function &F) const {
// function that reside in TargetOptions. // function that reside in TargetOptions.
resetTargetOptions(F); resetTargetOptions(F);
I = llvm::make_unique<X86Subtarget>(TargetTriple, CPU, FS, *this, I = llvm::make_unique<X86Subtarget>(TargetTriple, CPU, FS, *this,
Options.StackAlignmentOverride); Options.StackAlignmentOverride,
OptForSize, OptForMinSize);
#ifndef LLVM_BUILD_GLOBAL_ISEL #ifndef LLVM_BUILD_GLOBAL_ISEL
GISelAccessor *GISel = new GISelAccessor(); GISelAccessor *GISel = new GISelAccessor();
#else #else
@ -286,7 +293,8 @@ X86TargetMachine::getSubtargetImpl(const Function &F) const {
auto *RBI = new X86RegisterBankInfo(*I->getRegisterInfo()); auto *RBI = new X86RegisterBankInfo(*I->getRegisterInfo());
GISel->RegBankInfo.reset(RBI); GISel->RegBankInfo.reset(RBI);
GISel->InstSelector.reset(createX86InstructionSelector(*this, *I, *RBI)); GISel->InstSelector.reset(createX86InstructionSelector(
*this, *I, *RBI));
#endif #endif
I->setGISelAccessor(*GISel); I->setGISelAccessor(*GISel);
} }

View File

@ -0,0 +1,37 @@
# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=ALL,INC
# RUN: llc -mtriple=x86_64-linux-gnu -mattr=+slow-incdec -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=ALL,ADD
--- |
define i8 @test_add_i8(i8 %arg1) {
%ret = add i8 %arg1, 1
ret i8 %ret
}
...
---
name: test_add_i8
legalized: true
regBankSelected: true
# ALL: registers:
# ALL-NEXT: - { id: 0, class: gr8 }
# INC-NEXT: - { id: 1, class: gpr }
# ADD-NEXT: - { id: 1, class: gr8 }
# ALL-NEXT: - { id: 2, class: gr8 }
registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
# ALL: %0 = COPY %al
# INC-NEXT: %2 = INC8r %0
# ADD-NEXT: %1 = MOV8ri 1
# ADD-NEXT: %2 = ADD8rr %0, %1
body: |
bb.1 (%ir-block.0):
liveins: %al
%0(s8) = COPY %al
%1(s8) = G_CONSTANT i8 1
%2(s8) = G_ADD %0, %1
%al = COPY %2(s8)
...

View File

@ -32,22 +32,25 @@ def m1Z : OperandWithDefaultOps <i32, (ops (i32 -1), R0)>;
def HasA : Predicate<"Subtarget->hasA()">; def HasA : Predicate<"Subtarget->hasA()">;
def HasB : Predicate<"Subtarget->hasB()">; def HasB : Predicate<"Subtarget->hasB()">;
def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
//===- Test the function boilerplate. -------------------------------------===// //===- Test the function boilerplate. -------------------------------------===//
// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t { // CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
// CHECK-NEXT: Feature_HasABit = 0, // CHECK-NEXT: Feature_HasABit = 0,
// CHECK-NEXT: Feature_HasBBit = 1, // CHECK-NEXT: Feature_HasBBit = 1,
// CHECK-NEXT: Feature_HasCBit = 2,
// CHECK-NEXT: }; // CHECK-NEXT: };
// CHECK-LABEL: static const char *SubtargetFeatureNames[] = { // CHECK-LABEL: static const char *SubtargetFeatureNames[] = {
// CHECK-NEXT: "Feature_HasA", // CHECK-NEXT: "Feature_HasA",
// CHECK-NEXT: "Feature_HasB", // CHECK-NEXT: "Feature_HasB",
// CHECK-NEXT: "Feature_HasC",
// CHECK-NEXT: nullptr // CHECK-NEXT: nullptr
// CHECK-NEXT: }; // CHECK-NEXT: };
// CHECK-LABEL: PredicateBitset MyTargetInstructionSelector:: // CHECK-LABEL: PredicateBitset MyTargetInstructionSelector::
// CHECK-NEXT: computeAvailableFeatures(const MachineFunction *MF, const MyTargetSubtarget *Subtarget) const { // CHECK-NEXT: computeAvailableModuleFeatures(const MyTargetSubtarget *Subtarget) const {
// CHECK-NEXT: PredicateBitset Features; // CHECK-NEXT: PredicateBitset Features;
// CHECK-NEXT: if (Subtarget->hasA()) // CHECK-NEXT: if (Subtarget->hasA())
// CHECK-NEXT: Features[Feature_HasABit] = 1; // CHECK-NEXT: Features[Feature_HasABit] = 1;
@ -56,6 +59,14 @@ def HasB : Predicate<"Subtarget->hasB()">;
// CHECK-NEXT: return Features; // CHECK-NEXT: return Features;
// CHECK-NEXT: } // CHECK-NEXT: }
// CHECK-LABEL: PredicateBitset MyTargetInstructionSelector::
// CHECK-NEXT: computeAvailableFunctionFeatures(const MyTargetSubtarget *Subtarget, const MachineFunction *MF) const {
// CHECK-NEXT: PredicateBitset Features;
// CHECK-NEXT: if (Subtarget->hasC())
// CHECK-NEXT: Features[Feature_HasCBit] = 1;
// CHECK-NEXT: return Features;
// CHECK-NEXT: }
// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const { // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const {
// CHECK: MachineFunction &MF = *I.getParent()->getParent(); // CHECK: MachineFunction &MF = *I.getParent()->getParent();
// CHECK: const MachineRegisterInfo &MRI = MF.getRegInfo(); // CHECK: const MachineRegisterInfo &MRI = MF.getRegInfo();
@ -216,7 +227,7 @@ def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
//===- Test another simple pattern with regclass operands. ----------------===// //===- Test another simple pattern with regclass operands. ----------------===//
// CHECK-LABEL: if ([&]() { // CHECK-LABEL: if ([&]() {
// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit, Feature_HasBBit}; // CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit, Feature_HasBBit, Feature_HasCBit};
// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) // CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)
// CHECK-NEXT: return false; // CHECK-NEXT: return false;
// CHECK-NEXT: MachineInstr &MI0 = I; // CHECK-NEXT: MachineInstr &MI0 = I;
@ -247,7 +258,7 @@ def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1), def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
[(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>, [(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>,
Requires<[HasA, HasB]>; Requires<[HasA, HasB, HasC]>;
//===- Test a pattern with ComplexPattern operands. -----------------------===// //===- Test a pattern with ComplexPattern operands. -----------------------===//
// //

View File

@ -30,7 +30,8 @@ std::unique_ptr<TargetMachine> createTargetMachine() {
std::unique_ptr<AArch64InstrInfo> createInstrInfo(TargetMachine *TM) { std::unique_ptr<AArch64InstrInfo> createInstrInfo(TargetMachine *TM) {
AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(), AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(),
TM->getTargetFeatureString(), *TM, /* isLittle */ false); TM->getTargetFeatureString(), *TM, /* isLittle */ false,
/* ForCodeSize */ false);
return llvm::make_unique<AArch64InstrInfo>(ST); return llvm::make_unique<AArch64InstrInfo>(ST);
} }

View File

@ -199,21 +199,19 @@ public:
void emitCxxCapturedInsnList(raw_ostream &OS); void emitCxxCapturedInsnList(raw_ostream &OS);
void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr); void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr);
void emit(raw_ostream &OS, void emit(raw_ostream &OS, SubtargetFeatureInfoMap SubtargetFeatures);
std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
SubtargetFeatures);
/// Compare the priority of this object and B. /// Compare the priority of this object and B.
/// ///
/// Returns true if this object is more important than B. /// Returns true if this object is more important than B.
bool isHigherPriorityThan(const RuleMatcher &B) const; bool isHigherPriorityThan(const RuleMatcher &B) const;
/// Report the maximum number of temporary operands needed by the rule /// Report the maximum number of temporary operands needed by the rule
/// matcher. /// matcher.
unsigned countRendererFns() const; unsigned countRendererFns() const;
// FIXME: Remove this as soon as possible // FIXME: Remove this as soon as possible
InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); } InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); }
}; };
template <class PredicateTy> class PredicateListMatcher { template <class PredicateTy> class PredicateListMatcher {
@ -951,6 +949,9 @@ private:
/// True if the instruction can be built solely by mutating the opcode. /// True if the instruction can be built solely by mutating the opcode.
bool canMutate() const { bool canMutate() const {
if (OperandRenderers.size() != Matched.getNumOperands())
return false;
for (const auto &Renderer : enumerate(OperandRenderers)) { for (const auto &Renderer : enumerate(OperandRenderers)) {
if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) { if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {
const OperandMatcher &OM = Matched.getOperand(Copy->getSymbolicName()); const OperandMatcher &OM = Matched.getOperand(Copy->getSymbolicName());
@ -1072,8 +1073,7 @@ void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr) {
} }
void RuleMatcher::emit(raw_ostream &OS, void RuleMatcher::emit(raw_ostream &OS,
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatureInfoMap SubtargetFeatures) {
SubtargetFeatures) {
if (Matchers.empty()) if (Matchers.empty())
llvm_unreachable("Unexpected empty matcher!"); llvm_unreachable("Unexpected empty matcher!");
@ -1218,7 +1218,7 @@ private:
DenseMap<const Record *, const Record *> ComplexPatternEquivs; DenseMap<const Record *, const Record *> ComplexPatternEquivs;
// Map of predicates to their subtarget features. // Map of predicates to their subtarget features.
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures; SubtargetFeatureInfoMap SubtargetFeatures;
void gatherNodeEquivs(); void gatherNodeEquivs();
const CodeGenInstruction *findNodeEquiv(Record *N) const; const CodeGenInstruction *findNodeEquiv(Record *N) const;
@ -1713,14 +1713,36 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures, SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
OS); OS);
SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS); SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS);
// Separate subtarget features by how often they must be recomputed.
SubtargetFeatureInfoMap ModuleFeatures;
std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
std::inserter(ModuleFeatures, ModuleFeatures.end()),
[](const SubtargetFeatureInfoMap::value_type &X) {
return !X.second.mustRecomputePerFunction();
});
SubtargetFeatureInfoMap FunctionFeatures;
std::copy_if(SubtargetFeatures.begin(), SubtargetFeatures.end(),
std::inserter(FunctionFeatures, FunctionFeatures.end()),
[](const SubtargetFeatureInfoMap::value_type &X) {
return X.second.mustRecomputePerFunction();
});
SubtargetFeatureInfo::emitComputeAvailableFeatures( SubtargetFeatureInfo::emitComputeAvailableFeatures(
Target.getName(), "InstructionSelector", "computeAvailableFeatures", Target.getName(), "InstructionSelector", "computeAvailableModuleFeatures",
SubtargetFeatures, OS); ModuleFeatures, OS);
SubtargetFeatureInfo::emitComputeAvailableFeatures(
Target.getName(), "InstructionSelector",
"computeAvailableFunctionFeatures", FunctionFeatures, OS,
"const MachineFunction *MF");
OS << "bool " << Target.getName() OS << "bool " << Target.getName()
<< "InstructionSelector::selectImpl(MachineInstr &I) const {\n" << "InstructionSelector::selectImpl(MachineInstr &I) const {\n"
<< " MachineFunction &MF = *I.getParent()->getParent();\n" << " MachineFunction &MF = *I.getParent()->getParent();\n"
<< " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"; << " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
<< " // FIXME: This should be computed on a per-function basis rather than per-insn.\n"
<< " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, &MF);\n"
<< " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n";
for (auto &Rule : Rules) { for (auto &Rule : Rules) {
Rule.emit(OS, SubtargetFeatures); Rule.emit(OS, SubtargetFeatures);
@ -1730,6 +1752,26 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
OS << " return false;\n" OS << " return false;\n"
<< "}\n" << "}\n"
<< "#endif // ifdef GET_GLOBALISEL_IMPL\n"; << "#endif // ifdef GET_GLOBALISEL_IMPL\n";
OS << "#ifdef GET_GLOBALISEL_PREDICATES_DECL\n"
<< "PredicateBitset AvailableModuleFeatures;\n"
<< "mutable PredicateBitset AvailableFunctionFeatures;\n"
<< "PredicateBitset getAvailableFeatures() const {\n"
<< " return AvailableModuleFeatures | AvailableFunctionFeatures;\n"
<< "}\n"
<< "PredicateBitset\n"
<< "computeAvailableModuleFeatures(const " << Target.getName()
<< "Subtarget *Subtarget) const;\n"
<< "PredicateBitset\n"
<< "computeAvailableFunctionFeatures(const " << Target.getName()
<< "Subtarget *Subtarget,\n"
<< " const MachineFunction *MF) const;\n"
<< "#endif // ifdef GET_GLOBALISEL_PREDICATES_DECL\n";
OS << "#ifdef GET_GLOBALISEL_PREDICATES_INIT\n"
<< "AvailableModuleFeatures(computeAvailableModuleFeatures(&STI)),\n"
<< "AvailableFunctionFeatures()\n"
<< "#endif // ifdef GET_GLOBALISEL_PREDICATES_INIT\n";
} }
void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) { void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) {

View File

@ -45,8 +45,7 @@ SubtargetFeatureInfo::getAll(const RecordKeeper &Records) {
} }
void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration( void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures, SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
raw_ostream &OS) {
OS << "// Flags for subtarget features that participate in " OS << "// Flags for subtarget features that participate in "
<< "instruction matching.\n"; << "instruction matching.\n";
OS << "enum SubtargetFeatureFlag : " OS << "enum SubtargetFeatureFlag : "
@ -60,8 +59,7 @@ void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(
} }
void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration( void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures, SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
raw_ostream &OS) {
OS << "// Bits for subtarget features that participate in " OS << "// Bits for subtarget features that participate in "
<< "instruction matching.\n"; << "instruction matching.\n";
OS << "enum SubtargetFeatureBits : " OS << "enum SubtargetFeatureBits : "
@ -74,8 +72,7 @@ void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
} }
void SubtargetFeatureInfo::emitNameTable( void SubtargetFeatureInfo::emitNameTable(
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures, SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
raw_ostream &OS) {
// Need to sort the name table so that lookup by the log of the enum value // Need to sort the name table so that lookup by the log of the enum value
// gives the proper name. More specifically, for a feature of value 1<<n, // gives the proper name. More specifically, for a feature of value 1<<n,
// SubtargetFeatureNames[n] should be the name of the feature. // SubtargetFeatureNames[n] should be the name of the feature.
@ -102,11 +99,13 @@ void SubtargetFeatureInfo::emitNameTable(
void SubtargetFeatureInfo::emitComputeAvailableFeatures( void SubtargetFeatureInfo::emitComputeAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName, StringRef TargetName, StringRef ClassName, StringRef FuncName,
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures, SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS,
raw_ostream &OS) { StringRef ExtraParams) {
OS << "PredicateBitset " << TargetName << ClassName << "::\n" OS << "PredicateBitset " << TargetName << ClassName << "::\n"
<< FuncName << "(const MachineFunction *MF, const " << TargetName << FuncName << "(const " << TargetName << "Subtarget *Subtarget";
<< "Subtarget *Subtarget) const {\n"; if (!ExtraParams.empty())
OS << ", " << ExtraParams;
OS << ") const {\n";
OS << " PredicateBitset Features;\n"; OS << " PredicateBitset Features;\n";
for (const auto &SF : SubtargetFeatures) { for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second; const SubtargetFeatureInfo &SFI = SF.second;
@ -120,8 +119,7 @@ void SubtargetFeatureInfo::emitComputeAvailableFeatures(
void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName, StringRef TargetName, StringRef ClassName, StringRef FuncName,
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures, SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
raw_ostream &OS) {
OS << "uint64_t " << TargetName << ClassName << "::\n" OS << "uint64_t " << TargetName << ClassName << "::\n"
<< FuncName << "(const FeatureBitset& FB) const {\n"; << FuncName << "(const FeatureBitset& FB) const {\n";
OS << " uint64_t Features = 0;\n"; OS << " uint64_t Features = 0;\n";

View File

@ -21,6 +21,9 @@ namespace llvm {
class Record; class Record;
class RecordKeeper; class RecordKeeper;
struct SubtargetFeatureInfo;
using SubtargetFeatureInfoMap = std::map<Record *, SubtargetFeatureInfo, LessRecordByID>;
/// Helper class for storing information on a subtarget feature which /// Helper class for storing information on a subtarget feature which
/// participates in instruction matching. /// participates in instruction matching.
struct SubtargetFeatureInfo { struct SubtargetFeatureInfo {
@ -43,6 +46,10 @@ struct SubtargetFeatureInfo {
return "Feature_" + TheDef->getName().str() + "Bit"; return "Feature_" + TheDef->getName().str() + "Bit";
} }
bool mustRecomputePerFunction() const {
return TheDef->getValueAsBit("RecomputePerFunction");
}
void dump() const; void dump() const;
static std::vector<std::pair<Record *, SubtargetFeatureInfo>> static std::vector<std::pair<Record *, SubtargetFeatureInfo>>
getAll(const RecordKeeper &Records); getAll(const RecordKeeper &Records);
@ -52,21 +59,17 @@ struct SubtargetFeatureInfo {
/// This version emits the bit value for the feature and is therefore limited /// This version emits the bit value for the feature and is therefore limited
/// to 64 feature bits. /// to 64 feature bits.
static void emitSubtargetFeatureFlagEnumeration( static void emitSubtargetFeatureFlagEnumeration(
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS);
&SubtargetFeatures,
raw_ostream &OS);
/// Emit the subtarget feature flag definitions. /// Emit the subtarget feature flag definitions.
/// ///
/// This version emits the bit index for the feature and can therefore support /// This version emits the bit index for the feature and can therefore support
/// more than 64 feature bits. /// more than 64 feature bits.
static void emitSubtargetFeatureBitEnumeration( static void
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> emitSubtargetFeatureBitEnumeration(SubtargetFeatureInfoMap &SubtargetFeatures,
&SubtargetFeatures, raw_ostream &OS);
raw_ostream &OS);
static void emitNameTable(std::map<Record *, SubtargetFeatureInfo, static void emitNameTable(SubtargetFeatureInfoMap &SubtargetFeatures,
LessRecordByID> &SubtargetFeatures,
raw_ostream &OS); raw_ostream &OS);
/// Emit the function to compute the list of available features given a /// Emit the function to compute the list of available features given a
@ -82,11 +85,12 @@ struct SubtargetFeatureInfo {
/// \param FuncName The name of the function to emit. /// \param FuncName The name of the function to emit.
/// \param SubtargetFeatures A map of TableGen records to the /// \param SubtargetFeatures A map of TableGen records to the
/// SubtargetFeatureInfo equivalent. /// SubtargetFeatureInfo equivalent.
static void emitComputeAvailableFeatures( /// \param ExtraParams Additional arguments to the generated function.
StringRef TargetName, StringRef ClassName, StringRef FuncName, static void
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> emitComputeAvailableFeatures(StringRef TargetName, StringRef ClassName,
&SubtargetFeatures, StringRef FuncName,
raw_ostream &OS); SubtargetFeatureInfoMap &SubtargetFeatures,
raw_ostream &OS, StringRef ExtraParams = "");
/// Emit the function to compute the list of available features given a /// Emit the function to compute the list of available features given a
/// subtarget. /// subtarget.
@ -103,9 +107,7 @@ struct SubtargetFeatureInfo {
/// SubtargetFeatureInfo equivalent. /// SubtargetFeatureInfo equivalent.
static void emitComputeAssemblerAvailableFeatures( static void emitComputeAssemblerAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName, StringRef TargetName, StringRef ClassName, StringRef FuncName,
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS);
&SubtargetFeatures,
raw_ostream &OS);
}; };
} // end namespace llvm } // end namespace llvm