#include "X86Subtarget.h"
#include "MCTargetDesc/X86BaseInfo.h"
#include "X86.h"
#include "X86CallLowering.h"
#include "X86LegalizerInfo.h"
#include "X86MacroFusion.h"
#include "X86RegisterBankInfo.h"
#include "X86TargetMachine.h"
#include "llvm/ADT/Triple.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/ScheduleDAGMutation.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#if defined(_MSC_VER)
#include <intrin.h>
#endif
using namespace llvm;
#define DEBUG_TYPE "subtarget"
#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "X86GenSubtargetInfo.inc"
static cl::opt<bool>
X86EarlyIfConv("x86-early-ifcvt", cl::Hidden,
cl::desc("Enable early if-conversion on X86"));
unsigned char X86Subtarget::classifyBlockAddressReference() const {
return classifyLocalReference(nullptr);
}
unsigned char
X86Subtarget::classifyGlobalReference(const GlobalValue *GV) const {
return classifyGlobalReference(GV, *GV->getParent());
}
unsigned char
X86Subtarget::classifyLocalReference(const GlobalValue *GV) const {
if (AllowTaggedGlobals && TM.getCodeModel() == CodeModel::Small && GV &&
!isa<Function>(GV))
return X86II::MO_GOTPCREL_NORELAX;
if (!isPositionIndependent())
return X86II::MO_NO_FLAG;
if (is64Bit()) {
if (isTargetELF()) {
switch (TM.getCodeModel()) {
case CodeModel::Tiny:
llvm_unreachable("Tiny codesize model not supported on X86");
case CodeModel::Small:
case CodeModel::Kernel:
return X86II::MO_NO_FLAG;
case CodeModel::Large:
return X86II::MO_GOTOFF;
case CodeModel::Medium:
if (isa_and_nonnull<Function>(GV))
return X86II::MO_NO_FLAG; return X86II::MO_GOTOFF; }
llvm_unreachable("invalid code model");
}
return X86II::MO_NO_FLAG;
}
if (isTargetCOFF())
return X86II::MO_NO_FLAG;
if (isTargetDarwin()) {
if (GV && (GV->isDeclarationForLinker() || GV->hasCommonLinkage()))
return X86II::MO_DARWIN_NONLAZY_PIC_BASE;
return X86II::MO_PIC_BASE_OFFSET;
}
return X86II::MO_GOTOFF;
}
unsigned char X86Subtarget::classifyGlobalReference(const GlobalValue *GV,
const Module &M) const {
if (TM.getCodeModel() == CodeModel::Large && !isPositionIndependent())
return X86II::MO_NO_FLAG;
if (GV) {
if (Optional<ConstantRange> CR = GV->getAbsoluteSymbolRange()) {
if (CR->getUnsignedMax().ult(128))
return X86II::MO_ABS8;
else
return X86II::MO_NO_FLAG;
}
}
if (TM.shouldAssumeDSOLocal(M, GV))
return classifyLocalReference(GV);
if (isTargetCOFF()) {
if (!GV)
return X86II::MO_NO_FLAG;
if (GV->hasDLLImportStorageClass())
return X86II::MO_DLLIMPORT;
return X86II::MO_COFFSTUB;
}
if (isOSWindows())
return X86II::MO_NO_FLAG;
if (is64Bit()) {
if (TM.getCodeModel() == CodeModel::Large)
return isTargetELF() ? X86II::MO_GOT : X86II::MO_NO_FLAG;
if (AllowTaggedGlobals && GV && !isa<Function>(GV))
return X86II::MO_GOTPCREL_NORELAX;
return X86II::MO_GOTPCREL;
}
if (isTargetDarwin()) {
if (!isPositionIndependent())
return X86II::MO_DARWIN_NONLAZY;
return X86II::MO_DARWIN_NONLAZY_PIC_BASE;
}
if (TM.getRelocationModel() == Reloc::Static)
return X86II::MO_NO_FLAG;
return X86II::MO_GOT;
}
unsigned char
X86Subtarget::classifyGlobalFunctionReference(const GlobalValue *GV) const {
return classifyGlobalFunctionReference(GV, *GV->getParent());
}
unsigned char
X86Subtarget::classifyGlobalFunctionReference(const GlobalValue *GV,
const Module &M) const {
if (TM.shouldAssumeDSOLocal(M, GV))
return X86II::MO_NO_FLAG;
if (isTargetCOFF()) {
if (!GV)
return X86II::MO_NO_FLAG;
if (GV->hasDLLImportStorageClass())
return X86II::MO_DLLIMPORT;
return X86II::MO_COFFSTUB;
}
const Function *F = dyn_cast_or_null<Function>(GV);
if (isTargetELF()) {
if (is64Bit() && F && (CallingConv::X86_RegCall == F->getCallingConv()))
return X86II::MO_GOTPCREL;
if (((F && F->hasFnAttribute(Attribute::NonLazyBind)) ||
(!F && M.getRtLibUseGOT())) &&
is64Bit())
return X86II::MO_GOTPCREL;
if (!is64Bit() && !GV && TM.getRelocationModel() == Reloc::Static)
return X86II::MO_NO_FLAG;
return X86II::MO_PLT;
}
if (is64Bit()) {
if (F && F->hasFnAttribute(Attribute::NonLazyBind))
return X86II::MO_GOTPCREL;
return X86II::MO_NO_FLAG;
}
return X86II::MO_NO_FLAG;
}
bool X86Subtarget::isLegalToCallImmediateAddr() const {
if (Is64Bit || isTargetWin32())
return false;
return isTargetELF() || TM.getRelocationModel() == Reloc::Static;
}
void X86Subtarget::initSubtargetFeatures(StringRef CPU, StringRef TuneCPU,
StringRef FS) {
if (CPU.empty())
CPU = "generic";
if (TuneCPU.empty())
TuneCPU = "i586";
std::string FullFS = X86_MC::ParseX86Triple(TargetTriple);
assert(!FullFS.empty() && "Failed to parse X86 triple");
if (!FS.empty())
FullFS = (Twine(FullFS) + "," + FS).str();
ParseSubtargetFeatures(CPU, TuneCPU, FullFS);
if (hasSSE42() || hasSSE4A())
IsUnalignedMem16Slow = false;
LLVM_DEBUG(dbgs() << "Subtarget features: SSELevel " << X86SSELevel
<< ", 3DNowLevel " << X863DNowLevel << ", 64bit "
<< HasX86_64 << "\n");
if (Is64Bit && !HasX86_64)
report_fatal_error("64-bit code requested on a subtarget that doesn't "
"support it!");
if (StackAlignOverride)
stackAlignment = *StackAlignOverride;
else if (isTargetDarwin() || isTargetLinux() || isTargetKFreeBSD() ||
isTargetNaCl() || Is64Bit)
stackAlignment = Align(16);
if (PreferVectorWidthOverride)
PreferVectorWidth = PreferVectorWidthOverride;
else if (Prefer128Bit)
PreferVectorWidth = 128;
else if (Prefer256Bit)
PreferVectorWidth = 256;
}
X86Subtarget &X86Subtarget::initializeSubtargetDependencies(StringRef CPU,
StringRef TuneCPU,
StringRef FS) {
initSubtargetFeatures(CPU, TuneCPU, FS);
return *this;
}
X86Subtarget::X86Subtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU,
StringRef FS, const X86TargetMachine &TM,
MaybeAlign StackAlignOverride,
unsigned PreferVectorWidthOverride,
unsigned RequiredVectorWidth)
: X86GenSubtargetInfo(TT, CPU, TuneCPU, FS),
PICStyle(PICStyles::Style::None), TM(TM), TargetTriple(TT),
StackAlignOverride(StackAlignOverride),
PreferVectorWidthOverride(PreferVectorWidthOverride),
RequiredVectorWidth(RequiredVectorWidth),
InstrInfo(initializeSubtargetDependencies(CPU, TuneCPU, FS)),
TLInfo(TM, *this), FrameLowering(*this, getStackAlignment()) {
if (!isPositionIndependent())
setPICStyle(PICStyles::Style::None);
else if (is64Bit())
setPICStyle(PICStyles::Style::RIPRel);
else if (isTargetCOFF())
setPICStyle(PICStyles::Style::None);
else if (isTargetDarwin())
setPICStyle(PICStyles::Style::StubPIC);
else if (isTargetELF())
setPICStyle(PICStyles::Style::GOT);
CallLoweringInfo.reset(new X86CallLowering(*getTargetLowering()));
Legalizer.reset(new X86LegalizerInfo(*this, TM));
auto *RBI = new X86RegisterBankInfo(*getRegisterInfo());
RegBankInfo.reset(RBI);
InstSelector.reset(createX86InstructionSelector(TM, *this, *RBI));
}
const CallLowering *X86Subtarget::getCallLowering() const {
return CallLoweringInfo.get();
}
InstructionSelector *X86Subtarget::getInstructionSelector() const {
return InstSelector.get();
}
const LegalizerInfo *X86Subtarget::getLegalizerInfo() const {
return Legalizer.get();
}
const RegisterBankInfo *X86Subtarget::getRegBankInfo() const {
return RegBankInfo.get();
}
bool X86Subtarget::enableEarlyIfConversion() const {
return canUseCMOV() && X86EarlyIfConv;
}
void X86Subtarget::getPostRAMutations(
std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) const {
Mutations.push_back(createX86MacroFusionDAGMutation());
}
bool X86Subtarget::isPositionIndependent() const {
return TM.isPositionIndependent();
}