#include "X86TargetMachine.h"
#include "MCTargetDesc/X86MCTargetDesc.h"
#include "TargetInfo/X86TargetInfo.h"
#include "X86.h"
#include "X86CallLowering.h"
#include "X86LegalizerInfo.h"
#include "X86MacroFusion.h"
#include "X86Subtarget.h"
#include "X86TargetObjectFile.h"
#include "X86TargetTransformInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/CodeGen/ExecutionDomainFix.h"
#include "llvm/CodeGen/GlobalISel/CSEInfo.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/Legalizer.h"
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Pass.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/CFGuard.h"
#include <memory>
#include <string>
using namespace llvm;
static cl::opt<bool> EnableMachineCombinerPass("x86-machine-combiner",
cl::desc("Enable the machine combiner pass"),
cl::init(true), cl::Hidden);
static cl::opt<bool>
EnableTileRAPass("x86-tile-ra",
cl::desc("Enable the tile register allocation pass"),
cl::init(true), cl::Hidden);
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeX86Target() {
RegisterTargetMachine<X86TargetMachine> X(getTheX86_32Target());
RegisterTargetMachine<X86TargetMachine> Y(getTheX86_64Target());
PassRegistry &PR = *PassRegistry::getPassRegistry();
initializeX86LowerAMXIntrinsicsLegacyPassPass(PR);
initializeX86LowerAMXTypeLegacyPassPass(PR);
initializeX86PreAMXConfigPassPass(PR);
initializeX86PreTileConfigPass(PR);
initializeGlobalISel(PR);
initializeWinEHStatePassPass(PR);
initializeFixupBWInstPassPass(PR);
initializeEvexToVexInstPassPass(PR);
initializeFixupLEAPassPass(PR);
initializeFPSPass(PR);
initializeX86FixupSetCCPassPass(PR);
initializeX86CallFrameOptimizationPass(PR);
initializeX86CmovConverterPassPass(PR);
initializeX86TileConfigPass(PR);
initializeX86FastPreTileConfigPass(PR);
initializeX86FastTileConfigPass(PR);
initializeX86LowerTileCopyPass(PR);
initializeX86ExpandPseudoPass(PR);
initializeX86ExecutionDomainFixPass(PR);
initializeX86DomainReassignmentPass(PR);
initializeX86AvoidSFBPassPass(PR);
initializeX86AvoidTrailingCallPassPass(PR);
initializeX86SpeculativeLoadHardeningPassPass(PR);
initializeX86SpeculativeExecutionSideEffectSuppressionPass(PR);
initializeX86FlagsCopyLoweringPassPass(PR);
initializeX86LoadValueInjectionLoadHardeningPassPass(PR);
initializeX86LoadValueInjectionRetHardeningPassPass(PR);
initializeX86OptimizeLEAPassPass(PR);
initializeX86PartialReductionPass(PR);
initializePseudoProbeInserterPass(PR);
initializeX86ReturnThunksPass(PR);
}
static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
if (TT.isOSBinFormatMachO()) {
if (TT.getArch() == Triple::x86_64)
return std::make_unique<X86_64MachoTargetObjectFile>();
return std::make_unique<TargetLoweringObjectFileMachO>();
}
if (TT.isOSBinFormatCOFF())
return std::make_unique<TargetLoweringObjectFileCOFF>();
return std::make_unique<X86ELFTargetObjectFile>();
}
static std::string computeDataLayout(const Triple &TT) {
std::string Ret = "e";
Ret += DataLayout::getManglingComponent(TT);
if (!TT.isArch64Bit() || TT.isX32() || TT.isOSNaCl())
Ret += "-p:32:32";
Ret += "-p270:32:32-p271:32:32-p272:64:64";
if (TT.isArch64Bit() || TT.isOSWindows() || TT.isOSNaCl())
Ret += "-i64:64";
else if (TT.isOSIAMCU())
Ret += "-i64:32-f64:32";
else
Ret += "-f64:32:64";
if (TT.isOSNaCl() || TT.isOSIAMCU())
; else if (TT.isArch64Bit() || TT.isOSDarwin() || TT.isWindowsMSVCEnvironment())
Ret += "-f80:128";
else
Ret += "-f80:32";
if (TT.isOSIAMCU())
Ret += "-f128:32";
if (TT.isArch64Bit())
Ret += "-n8:16:32:64";
else
Ret += "-n8:16:32";
if ((!TT.isArch64Bit() && TT.isOSWindows()) || TT.isOSIAMCU())
Ret += "-a:0:32-S32";
else
Ret += "-S128";
return Ret;
}
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
bool JIT,
Optional<Reloc::Model> RM) {
bool is64Bit = TT.getArch() == Triple::x86_64;
if (!RM) {
if (JIT)
return Reloc::Static;
if (TT.isOSDarwin()) {
if (is64Bit)
return Reloc::PIC_;
return Reloc::DynamicNoPIC;
}
if (TT.isOSWindows() && is64Bit)
return Reloc::PIC_;
return Reloc::Static;
}
if (*RM == Reloc::DynamicNoPIC) {
if (is64Bit)
return Reloc::PIC_;
if (!TT.isOSDarwin())
return Reloc::Static;
}
if (*RM == Reloc::Static && TT.isOSDarwin() && is64Bit)
return Reloc::PIC_;
return *RM;
}
static CodeModel::Model getEffectiveX86CodeModel(Optional<CodeModel::Model> CM,
bool JIT, bool Is64Bit) {
if (CM) {
if (*CM == CodeModel::Tiny)
report_fatal_error("Target does not support the tiny CodeModel", false);
return *CM;
}
if (JIT)
return Is64Bit ? CodeModel::Large : CodeModel::Small;
return CodeModel::Small;
}
X86TargetMachine::X86TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
const TargetOptions &Options,
Optional<Reloc::Model> RM,
Optional<CodeModel::Model> CM,
CodeGenOpt::Level OL, bool JIT)
: LLVMTargetMachine(
T, computeDataLayout(TT), TT, CPU, FS, Options,
getEffectiveRelocModel(TT, JIT, RM),
getEffectiveX86CodeModel(CM, JIT, TT.getArch() == Triple::x86_64),
OL),
TLOF(createTLOF(getTargetTriple())), IsJIT(JIT) {
if (TT.isPS() || TT.isOSBinFormatMachO()) {
this->Options.TrapUnreachable = true;
this->Options.NoTrapAfterNoreturn = TT.isOSBinFormatMachO();
}
setMachineOutliner(true);
setSupportsDebugEntryValues(true);
initAsmInfo();
}
X86TargetMachine::~X86TargetMachine() = default;
const X86Subtarget *
X86TargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu");
Attribute TuneAttr = F.getFnAttribute("tune-cpu");
Attribute FSAttr = F.getFnAttribute("target-features");
StringRef CPU =
CPUAttr.isValid() ? CPUAttr.getValueAsString() : (StringRef)TargetCPU;
StringRef TuneCPU = TuneAttr.isValid() ? TuneAttr.getValueAsString()
: CPU == "x86-64" ? "generic"
: (StringRef)CPU;
StringRef FS =
FSAttr.isValid() ? FSAttr.getValueAsString() : (StringRef)TargetFS;
SmallString<512> Key;
unsigned PreferVectorWidthOverride = 0;
Attribute PreferVecWidthAttr = F.getFnAttribute("prefer-vector-width");
if (PreferVecWidthAttr.isValid()) {
StringRef Val = PreferVecWidthAttr.getValueAsString();
unsigned Width;
if (!Val.getAsInteger(0, Width)) {
Key += 'p';
Key += Val;
PreferVectorWidthOverride = Width;
}
}
unsigned RequiredVectorWidth = UINT32_MAX;
Attribute MinLegalVecWidthAttr = F.getFnAttribute("min-legal-vector-width");
if (MinLegalVecWidthAttr.isValid()) {
StringRef Val = MinLegalVecWidthAttr.getValueAsString();
unsigned Width;
if (!Val.getAsInteger(0, Width)) {
Key += 'm';
Key += Val;
RequiredVectorWidth = Width;
}
}
Key += CPU;
Key += TuneCPU;
unsigned FSStart = Key.size();
bool SoftFloat = F.getFnAttribute("use-soft-float").getValueAsBool();
if (SoftFloat)
Key += FS.empty() ? "+soft-float" : "+soft-float,";
Key += FS;
FS = Key.substr(FSStart);
auto &I = SubtargetMap[Key];
if (!I) {
resetTargetOptions(F);
I = std::make_unique<X86Subtarget>(
TargetTriple, CPU, TuneCPU, FS, *this,
MaybeAlign(F.getParent()->getOverrideStackAlignment()),
PreferVectorWidthOverride, RequiredVectorWidth);
}
return I.get();
}
bool X86TargetMachine::isNoopAddrSpaceCast(unsigned SrcAS,
unsigned DestAS) const {
assert(SrcAS != DestAS && "Expected different address spaces!");
if (getPointerSize(SrcAS) != getPointerSize(DestAS))
return false;
return SrcAS < 256 && DestAS < 256;
}
TargetTransformInfo
X86TargetMachine::getTargetTransformInfo(const Function &F) const {
return TargetTransformInfo(X86TTIImpl(this, F));
}
namespace {
class X86PassConfig : public TargetPassConfig {
public:
X86PassConfig(X86TargetMachine &TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {}
X86TargetMachine &getX86TargetMachine() const {
return getTM<X86TargetMachine>();
}
ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext *C) const override {
ScheduleDAGMILive *DAG = createGenericSchedLive(C);
DAG->addMutation(createX86MacroFusionDAGMutation());
return DAG;
}
ScheduleDAGInstrs *
createPostMachineScheduler(MachineSchedContext *C) const override {
ScheduleDAGMI *DAG = createGenericSchedPostRA(C);
DAG->addMutation(createX86MacroFusionDAGMutation());
return DAG;
}
void addIRPasses() override;
bool addInstSelector() override;
bool addIRTranslator() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
bool addGlobalInstructionSelect() override;
bool addILPOpts() override;
bool addPreISel() override;
void addMachineSSAOptimization() override;
void addPreRegAlloc() override;
bool addPostFastRegAllocRewrite() override;
void addPostRegAlloc() override;
void addPreEmitPass() override;
void addPreEmitPass2() override;
void addPreSched2() override;
bool addRegAssignAndRewriteOptimized() override;
std::unique_ptr<CSEConfigBase> getCSEConfig() const override;
};
class X86ExecutionDomainFix : public ExecutionDomainFix {
public:
static char ID;
X86ExecutionDomainFix() : ExecutionDomainFix(ID, X86::VR128XRegClass) {}
StringRef getPassName() const override {
return "X86 Execution Dependency Fix";
}
};
char X86ExecutionDomainFix::ID;
}
INITIALIZE_PASS_BEGIN(X86ExecutionDomainFix, "x86-execution-domain-fix",
"X86 Execution Domain Fix", false, false)
INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis)
INITIALIZE_PASS_END(X86ExecutionDomainFix, "x86-execution-domain-fix",
"X86 Execution Domain Fix", false, false)
TargetPassConfig *X86TargetMachine::createPassConfig(PassManagerBase &PM) {
return new X86PassConfig(*this, PM);
}
void X86PassConfig::addIRPasses() {
addPass(createAtomicExpandPass());
addPass(createX86LowerAMXIntrinsicsPass());
addPass(createX86LowerAMXTypePass());
TargetPassConfig::addIRPasses();
if (TM->getOptLevel() != CodeGenOpt::None) {
addPass(createInterleavedAccessPass());
addPass(createX86PartialReductionPass());
}
addPass(createIndirectBrExpandPass());
const Triple &TT = TM->getTargetTriple();
if (TT.isOSWindows()) {
if (TT.getArch() == Triple::x86_64) {
addPass(createCFGuardDispatchPass());
} else {
addPass(createCFGuardCheckPass());
}
}
if (TM->Options.JMCInstrument)
addPass(createJMCInstrumenterPass());
}
bool X86PassConfig::addInstSelector() {
addPass(createX86ISelDag(getX86TargetMachine(), getOptLevel()));
if (TM->getTargetTriple().isOSBinFormatELF() &&
getOptLevel() != CodeGenOpt::None)
addPass(createCleanupLocalDynamicTLSPass());
addPass(createX86GlobalBaseRegPass());
return false;
}
bool X86PassConfig::addIRTranslator() {
addPass(new IRTranslator(getOptLevel()));
return false;
}
bool X86PassConfig::addLegalizeMachineIR() {
addPass(new Legalizer());
return false;
}
bool X86PassConfig::addRegBankSelect() {
addPass(new RegBankSelect());
return false;
}
bool X86PassConfig::addGlobalInstructionSelect() {
addPass(new InstructionSelect(getOptLevel()));
return false;
}
bool X86PassConfig::addILPOpts() {
addPass(&EarlyIfConverterID);
if (EnableMachineCombinerPass)
addPass(&MachineCombinerID);
addPass(createX86CmovConverterPass());
return true;
}
bool X86PassConfig::addPreISel() {
const Triple &TT = TM->getTargetTriple();
if (TT.isOSWindows() && TT.getArch() == Triple::x86)
addPass(createX86WinEHStatePass());
return true;
}
void X86PassConfig::addPreRegAlloc() {
if (getOptLevel() != CodeGenOpt::None) {
addPass(&LiveRangeShrinkID);
addPass(createX86FixupSetCC());
addPass(createX86OptimizeLEAs());
addPass(createX86CallFrameOptimization());
addPass(createX86AvoidStoreForwardingBlocks());
}
addPass(createX86SpeculativeLoadHardeningPass());
addPass(createX86FlagsCopyLoweringPass());
addPass(createX86DynAllocaExpander());
if (getOptLevel() != CodeGenOpt::None)
addPass(createX86PreTileConfigPass());
else
addPass(createX86FastPreTileConfigPass());
}
void X86PassConfig::addMachineSSAOptimization() {
addPass(createX86DomainReassignmentPass());
TargetPassConfig::addMachineSSAOptimization();
}
void X86PassConfig::addPostRegAlloc() {
addPass(createX86LowerTileCopyPass());
addPass(createX86FloatingPointStackifierPass());
if (getOptLevel() != CodeGenOpt::None)
addPass(createX86LoadValueInjectionLoadHardeningPass());
}
void X86PassConfig::addPreSched2() { addPass(createX86ExpandPseudoPass()); }
void X86PassConfig::addPreEmitPass() {
if (getOptLevel() != CodeGenOpt::None) {
addPass(new X86ExecutionDomainFix());
addPass(createBreakFalseDeps());
}
addPass(createX86IndirectBranchTrackingPass());
addPass(createX86IssueVZeroUpperPass());
if (getOptLevel() != CodeGenOpt::None) {
addPass(createX86FixupBWInsts());
addPass(createX86PadShortFunctions());
addPass(createX86FixupLEAs());
}
addPass(createX86EvexToVexInsts());
addPass(createX86DiscriminateMemOpsPass());
addPass(createX86InsertPrefetchPass());
addPass(createX86InsertX87waitPass());
}
void X86PassConfig::addPreEmitPass2() {
const Triple &TT = TM->getTargetTriple();
const MCAsmInfo *MAI = TM->getMCAsmInfo();
addPass(createX86SpeculativeExecutionSideEffectSuppression());
addPass(createX86IndirectThunksPass());
addPass(createX86ReturnThunksPass());
if (TT.isOSWindows() && TT.getArch() == Triple::x86_64)
addPass(createX86AvoidTrailingCallPass());
if (!TT.isOSDarwin() &&
(!TT.isOSWindows() ||
MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI))
addPass(createCFIInstrInserter());
if (TT.isOSWindows()) {
addPass(createCFGuardLongjmpPass());
addPass(createEHContGuardCatchretPass());
}
addPass(createX86LoadValueInjectionRetHardeningPass());
addPass(createPseudoProbeInserter());
if (TT.isOSDarwin())
addPass(createUnpackMachineBundles([](const MachineFunction &MF) {
const Function &F = MF.getFunction();
const Module *M = F.getParent();
return M->getFunction("objc_retainAutoreleasedReturnValue") ||
M->getFunction("objc_unsafeClaimAutoreleasedReturnValue");
}));
}
bool X86PassConfig::addPostFastRegAllocRewrite() {
addPass(createX86FastTileConfigPass());
return true;
}
std::unique_ptr<CSEConfigBase> X86PassConfig::getCSEConfig() const {
return getStandardCSEConfigForOpt(TM->getOptLevel());
}
static bool onlyAllocateTileRegisters(const TargetRegisterInfo &TRI,
const TargetRegisterClass &RC) {
return static_cast<const X86RegisterInfo &>(TRI).isTileRegisterClass(&RC);
}
bool X86PassConfig::addRegAssignAndRewriteOptimized() {
if (!isCustomizedRegAlloc() && EnableTileRAPass) {
addPass(createGreedyRegisterAllocator(onlyAllocateTileRegisters));
addPass(createX86TileConfigPass());
}
return TargetPassConfig::addRegAssignAndRewriteOptimized();
}