#include "PPCTargetMachine.h"
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "PPC.h"
#include "PPCMachineScheduler.h"
#include "PPCMacroFusion.h"
#include "PPCSubtarget.h"
#include "PPCTargetObjectFile.h"
#include "PPCTargetTransformInfo.h"
#include "TargetInfo/PowerPCTargetInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetTransformInfo.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/Localizer.h"
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Pass.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
#include <cassert>
#include <memory>
#include <string>
using namespace llvm;
static cl::opt<bool>
EnableBranchCoalescing("enable-ppc-branch-coalesce", cl::Hidden,
cl::desc("enable coalescing of duplicate branches for PPC"));
static cl::
opt<bool> DisableCTRLoops("disable-ppc-ctrloops", cl::Hidden,
cl::desc("Disable CTR loops for PPC"));
static cl::
opt<bool> DisableInstrFormPrep("disable-ppc-instr-form-prep", cl::Hidden,
cl::desc("Disable PPC loop instr form prep"));
static cl::opt<bool>
VSXFMAMutateEarly("schedule-ppc-vsx-fma-mutation-early",
cl::Hidden, cl::desc("Schedule VSX FMA instruction mutation early"));
static cl::
opt<bool> DisableVSXSwapRemoval("disable-ppc-vsx-swap-removal", cl::Hidden,
cl::desc("Disable VSX Swap Removal for PPC"));
static cl::
opt<bool> DisableMIPeephole("disable-ppc-peephole", cl::Hidden,
cl::desc("Disable machine peepholes for PPC"));
static cl::opt<bool>
EnableGEPOpt("ppc-gep-opt", cl::Hidden,
cl::desc("Enable optimizations on complex GEPs"),
cl::init(true));
static cl::opt<bool>
EnablePrefetch("enable-ppc-prefetching",
cl::desc("enable software prefetching on PPC"),
cl::init(false), cl::Hidden);
static cl::opt<bool>
EnableExtraTOCRegDeps("enable-ppc-extra-toc-reg-deps",
cl::desc("Add extra TOC register dependencies"),
cl::init(true), cl::Hidden);
static cl::opt<bool>
EnableMachineCombinerPass("ppc-machine-combiner",
cl::desc("Enable the machine combiner pass"),
cl::init(true), cl::Hidden);
static cl::opt<bool>
ReduceCRLogical("ppc-reduce-cr-logicals",
cl::desc("Expand eligible cr-logical binary ops to branches"),
cl::init(true), cl::Hidden);
static cl::opt<bool> EnablePPCGenScalarMASSEntries(
"enable-ppc-gen-scalar-mass", cl::init(false),
cl::desc("Enable lowering math functions to their corresponding MASS "
"(scalar) entries"),
cl::Hidden);
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCTarget() {
RegisterTargetMachine<PPCTargetMachine> A(getThePPC32Target());
RegisterTargetMachine<PPCTargetMachine> B(getThePPC32LETarget());
RegisterTargetMachine<PPCTargetMachine> C(getThePPC64Target());
RegisterTargetMachine<PPCTargetMachine> D(getThePPC64LETarget());
PassRegistry &PR = *PassRegistry::getPassRegistry();
#ifndef NDEBUG
initializePPCCTRLoopsVerifyPass(PR);
#endif
initializePPCLoopInstrFormPrepPass(PR);
initializePPCTOCRegDepsPass(PR);
initializePPCEarlyReturnPass(PR);
initializePPCVSXCopyPass(PR);
initializePPCVSXFMAMutatePass(PR);
initializePPCVSXSwapRemovalPass(PR);
initializePPCReduceCRLogicalsPass(PR);
initializePPCBSelPass(PR);
initializePPCBranchCoalescingPass(PR);
initializePPCBoolRetToIntPass(PR);
initializePPCExpandISELPass(PR);
initializePPCPreEmitPeepholePass(PR);
initializePPCTLSDynamicCallPass(PR);
initializePPCMIPeepholePass(PR);
initializePPCLowerMASSVEntriesPass(PR);
initializePPCGenScalarMASSEntriesPass(PR);
initializePPCExpandAtomicPseudoPass(PR);
initializeGlobalISel(PR);
initializePPCCTRLoopsPass(PR);
}
static bool isLittleEndianTriple(const Triple &T) {
return T.getArch() == Triple::ppc64le || T.getArch() == Triple::ppcle;
}
static std::string getDataLayoutString(const Triple &T) {
bool is64Bit = T.getArch() == Triple::ppc64 || T.getArch() == Triple::ppc64le;
std::string Ret;
if (isLittleEndianTriple(T))
Ret = "e";
else
Ret = "E";
Ret += DataLayout::getManglingComponent(T);
if (!is64Bit || T.getOS() == Triple::Lv2)
Ret += "-p:32:32";
Ret += "-i64:64";
if (is64Bit)
Ret += "-n32:64";
else
Ret += "-n32";
if (is64Bit && (T.isOSAIX() || T.isOSLinux()))
Ret += "-S128-v256:256:256-v512:512:512";
return Ret;
}
static std::string computeFSAdditions(StringRef FS, CodeGenOpt::Level OL,
const Triple &TT) {
std::string FullFS = std::string(FS);
if (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le) {
if (!FullFS.empty())
FullFS = "+64bit," + FullFS;
else
FullFS = "+64bit";
}
if (OL >= CodeGenOpt::Default) {
if (!FullFS.empty())
FullFS = "+crbits," + FullFS;
else
FullFS = "+crbits";
}
if (OL != CodeGenOpt::None) {
if (!FullFS.empty())
FullFS = "+invariant-function-descriptors," + FullFS;
else
FullFS = "+invariant-function-descriptors";
}
if (TT.isOSAIX()) {
if (!FullFS.empty())
FullFS = "+aix," + FullFS;
else
FullFS = "+aix";
}
return FullFS;
}
static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
if (TT.isOSAIX())
return std::make_unique<TargetLoweringObjectFileXCOFF>();
return std::make_unique<PPC64LinuxTargetObjectFile>();
}
static PPCTargetMachine::PPCABI computeTargetABI(const Triple &TT,
const TargetOptions &Options) {
if (Options.MCOptions.getABIName().startswith("elfv1"))
return PPCTargetMachine::PPC_ABI_ELFv1;
else if (Options.MCOptions.getABIName().startswith("elfv2"))
return PPCTargetMachine::PPC_ABI_ELFv2;
assert(Options.MCOptions.getABIName().empty() &&
"Unknown target-abi option!");
if (TT.isMacOSX())
return PPCTargetMachine::PPC_ABI_UNKNOWN;
switch (TT.getArch()) {
case Triple::ppc64le:
return PPCTargetMachine::PPC_ABI_ELFv2;
case Triple::ppc64:
return PPCTargetMachine::PPC_ABI_ELFv1;
default:
return PPCTargetMachine::PPC_ABI_UNKNOWN;
}
}
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
Optional<Reloc::Model> RM) {
assert((!TT.isOSAIX() || !RM || *RM == Reloc::PIC_) &&
"Invalid relocation model for AIX.");
if (RM)
return *RM;
if (TT.getArch() == Triple::ppc64 || TT.isOSAIX())
return Reloc::PIC_;
return Reloc::Static;
}
static CodeModel::Model getEffectivePPCCodeModel(const Triple &TT,
Optional<CodeModel::Model> CM,
bool JIT) {
if (CM) {
if (*CM == CodeModel::Tiny)
report_fatal_error("Target does not support the tiny CodeModel", false);
if (*CM == CodeModel::Kernel)
report_fatal_error("Target does not support the kernel CodeModel", false);
return *CM;
}
if (JIT)
return CodeModel::Small;
if (TT.isOSAIX())
return CodeModel::Small;
assert(TT.isOSBinFormatELF() && "All remaining PPC OSes are ELF based.");
if (TT.isArch32Bit())
return CodeModel::Small;
assert(TT.isArch64Bit() && "Unsupported PPC architecture.");
return CodeModel::Medium;
}
static ScheduleDAGInstrs *createPPCMachineScheduler(MachineSchedContext *C) {
const PPCSubtarget &ST = C->MF->getSubtarget<PPCSubtarget>();
ScheduleDAGMILive *DAG =
new ScheduleDAGMILive(C, ST.usePPCPreRASchedStrategy() ?
std::make_unique<PPCPreRASchedStrategy>(C) :
std::make_unique<GenericScheduler>(C));
DAG->addMutation(createCopyConstrainDAGMutation(DAG->TII, DAG->TRI));
if (ST.hasStoreFusion())
DAG->addMutation(createStoreClusterDAGMutation(DAG->TII, DAG->TRI));
if (ST.hasFusion())
DAG->addMutation(createPowerPCMacroFusionDAGMutation());
return DAG;
}
static ScheduleDAGInstrs *createPPCPostMachineScheduler(
MachineSchedContext *C) {
const PPCSubtarget &ST = C->MF->getSubtarget<PPCSubtarget>();
ScheduleDAGMI *DAG =
new ScheduleDAGMI(C, ST.usePPCPostRASchedStrategy() ?
std::make_unique<PPCPostRASchedStrategy>(C) :
std::make_unique<PostGenericScheduler>(C), true);
if (ST.hasStoreFusion())
DAG->addMutation(createStoreClusterDAGMutation(DAG->TII, DAG->TRI));
if (ST.hasFusion())
DAG->addMutation(createPowerPCMacroFusionDAGMutation());
return DAG;
}
PPCTargetMachine::PPCTargetMachine(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, getDataLayoutString(TT), TT, CPU,
computeFSAdditions(FS, OL, TT), Options,
getEffectiveRelocModel(TT, RM),
getEffectivePPCCodeModel(TT, CM, JIT), OL),
TLOF(createTLOF(getTargetTriple())),
TargetABI(computeTargetABI(TT, Options)),
Endianness(isLittleEndianTriple(TT) ? Endian::LITTLE : Endian::BIG) {
initAsmInfo();
}
PPCTargetMachine::~PPCTargetMachine() = default;
const PPCSubtarget *
PPCTargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu");
Attribute FSAttr = F.getFnAttribute("target-features");
std::string CPU =
CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
std::string FS =
FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
bool SoftFloat = F.getFnAttribute("use-soft-float").getValueAsBool();
if (SoftFloat)
FS += FS.empty() ? "-hard-float" : ",-hard-float";
auto &I = SubtargetMap[CPU + FS];
if (!I) {
resetTargetOptions(F);
I = std::make_unique<PPCSubtarget>(
TargetTriple, CPU,
computeFSAdditions(FS, getOptLevel(), getTargetTriple()), *this);
}
return I.get();
}
namespace {
class PPCPassConfig : public TargetPassConfig {
public:
PPCPassConfig(PPCTargetMachine &TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {
if (TM.getOptLevel() != CodeGenOpt::None)
substitutePass(&PostRASchedulerID, &PostMachineSchedulerID);
}
PPCTargetMachine &getPPCTargetMachine() const {
return getTM<PPCTargetMachine>();
}
void addIRPasses() override;
bool addPreISel() override;
bool addILPOpts() override;
bool addInstSelector() override;
void addMachineSSAOptimization() override;
void addPreRegAlloc() override;
void addPreSched2() override;
void addPreEmitPass() override;
void addPreEmitPass2() override;
bool addIRTranslator() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
bool addGlobalInstructionSelect() override;
ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext *C) const override {
return createPPCMachineScheduler(C);
}
ScheduleDAGInstrs *
createPostMachineScheduler(MachineSchedContext *C) const override {
return createPPCPostMachineScheduler(C);
}
};
}
TargetPassConfig *PPCTargetMachine::createPassConfig(PassManagerBase &PM) {
return new PPCPassConfig(*this, PM);
}
void PPCPassConfig::addIRPasses() {
if (TM->getOptLevel() != CodeGenOpt::None)
addPass(createPPCBoolRetToIntPass());
addPass(createAtomicExpandPass());
addPass(createPPCLowerMASSVEntriesPass());
if (TM->getOptLevel() == CodeGenOpt::Aggressive &&
EnablePPCGenScalarMASSEntries) {
TM->Options.PPCGenScalarMASSEntries = EnablePPCGenScalarMASSEntries;
addPass(createPPCGenScalarMASSEntriesPass());
}
if (EnablePrefetch.getNumOccurrences() > 0)
addPass(createLoopDataPrefetchPass());
if (TM->getOptLevel() >= CodeGenOpt::Default && EnableGEPOpt) {
addPass(createSeparateConstOffsetFromGEPPass(true));
addPass(createEarlyCSEPass());
addPass(createLICMPass());
}
TargetPassConfig::addIRPasses();
}
bool PPCPassConfig::addPreISel() {
if (!DisableInstrFormPrep && getOptLevel() != CodeGenOpt::None)
addPass(createPPCLoopInstrFormPrepPass(getPPCTargetMachine()));
if (!DisableCTRLoops && getOptLevel() != CodeGenOpt::None)
addPass(createHardwareLoopsPass());
return false;
}
bool PPCPassConfig::addILPOpts() {
addPass(&EarlyIfConverterID);
if (EnableMachineCombinerPass)
addPass(&MachineCombinerID);
return true;
}
bool PPCPassConfig::addInstSelector() {
addPass(createPPCISelDag(getPPCTargetMachine(), getOptLevel()));
#ifndef NDEBUG
if (!DisableCTRLoops && getOptLevel() != CodeGenOpt::None)
addPass(createPPCCTRLoopsVerify());
#endif
addPass(createPPCVSXCopyPass());
return false;
}
void PPCPassConfig::addMachineSSAOptimization() {
if (EnableBranchCoalescing && getOptLevel() != CodeGenOpt::None)
addPass(createPPCBranchCoalescingPass());
TargetPassConfig::addMachineSSAOptimization();
if (TM->getTargetTriple().getArch() == Triple::ppc64le &&
!DisableVSXSwapRemoval)
addPass(createPPCVSXSwapRemovalPass());
if (ReduceCRLogical && getOptLevel() != CodeGenOpt::None)
addPass(createPPCReduceCRLogicalsPass());
if (!DisableMIPeephole) {
addPass(createPPCMIPeepholePass());
addPass(&DeadMachineInstructionElimID);
}
}
void PPCPassConfig::addPreRegAlloc() {
if (getOptLevel() != CodeGenOpt::None) {
initializePPCVSXFMAMutatePass(*PassRegistry::getPassRegistry());
insertPass(VSXFMAMutateEarly ? &RegisterCoalescerID : &MachineSchedulerID,
&PPCVSXFMAMutateID);
}
if (getPPCTargetMachine().isPositionIndependent()) {
addPass(&LiveVariablesID);
addPass(createPPCTLSDynamicCallPass());
}
if (EnableExtraTOCRegDeps)
addPass(createPPCTOCRegDepsPass());
if (getOptLevel() != CodeGenOpt::None)
addPass(createPPCCTRLoopsPass());
if (getOptLevel() != CodeGenOpt::None)
addPass(&MachinePipelinerID);
}
void PPCPassConfig::addPreSched2() {
if (getOptLevel() != CodeGenOpt::None)
addPass(&IfConverterID);
}
void PPCPassConfig::addPreEmitPass() {
addPass(createPPCPreEmitPeepholePass());
addPass(createPPCExpandISELPass());
if (getOptLevel() != CodeGenOpt::None)
addPass(createPPCEarlyReturnPass());
}
void PPCPassConfig::addPreEmitPass2() {
addPass(createPPCExpandAtomicPseudoPass());
addPass(createPPCBranchSelectionPass());
}
TargetTransformInfo
PPCTargetMachine::getTargetTransformInfo(const Function &F) const {
return TargetTransformInfo(PPCTTIImpl(this, F));
}
bool PPCTargetMachine::isLittleEndian() const {
assert(Endianness != Endian::NOT_DETECTED &&
"Unable to determine endianness");
return Endianness == Endian::LITTLE;
}
static MachineSchedRegistry
PPCPreRASchedRegistry("ppc-prera",
"Run PowerPC PreRA specific scheduler",
createPPCMachineScheduler);
static MachineSchedRegistry
PPCPostRASchedRegistry("ppc-postra",
"Run PowerPC PostRA specific scheduler",
createPPCPostMachineScheduler);
bool PPCPassConfig::addIRTranslator() {
addPass(new IRTranslator());
return false;
}
bool PPCPassConfig::addLegalizeMachineIR() {
addPass(new Legalizer());
return false;
}
bool PPCPassConfig::addRegBankSelect() {
addPass(new RegBankSelect());
return false;
}
bool PPCPassConfig::addGlobalInstructionSelect() {
addPass(new InstructionSelect(getOptLevel()));
return false;
}