diff --git a/llvm/lib/Target/SystemZ/SystemZTDC.cpp b/llvm/lib/Target/SystemZ/SystemZTDC.cpp --- a/llvm/lib/Target/SystemZ/SystemZTDC.cpp +++ b/llvm/lib/Target/SystemZ/SystemZTDC.cpp @@ -44,7 +44,9 @@ //===----------------------------------------------------------------------===// #include "SystemZ.h" +#include "SystemZSubtarget.h" #include "llvm/ADT/MapVector.h" +#include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Constants.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" @@ -72,6 +74,11 @@ } bool runOnFunction(Function &F) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + } + private: // Maps seen instructions that can be mapped to a TDC, values are // (TDC operand, TDC mask, worthy flag) triples. @@ -310,6 +317,12 @@ } bool SystemZTDCPass::runOnFunction(Function &F) { + auto &TPC = getAnalysis(); + if (TPC.getTM() + .getSubtarget(F) + .hasSoftFloat()) + return false; + ConvertedInsts.clear(); LogicOpsWorklist.clear(); PossibleJunk.clear(); diff --git a/llvm/lib/Target/SystemZ/SystemZTargetMachine.h b/llvm/lib/Target/SystemZ/SystemZTargetMachine.h --- a/llvm/lib/Target/SystemZ/SystemZTargetMachine.h +++ b/llvm/lib/Target/SystemZ/SystemZTargetMachine.h @@ -26,7 +26,8 @@ class SystemZTargetMachine : public LLVMTargetMachine { std::unique_ptr TLOF; - SystemZSubtarget Subtarget; + + mutable StringMap> SubtargetMap; public: SystemZTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -35,11 +36,11 @@ CodeGenOpt::Level OL, bool JIT); ~SystemZTargetMachine() override; - const SystemZSubtarget *getSubtargetImpl() const { return &Subtarget; } - - const SystemZSubtarget *getSubtargetImpl(const Function &) const override { - return &Subtarget; - } + const SystemZSubtarget *getSubtargetImpl(const Function &) const override; + // DO NOT IMPLEMENT: There is no such thing as a valid default subtarget, + // subtargets are per-function entities based on the target-specific + // attributes of each function. + const SystemZSubtarget *getSubtargetImpl() const = delete; // Override LLVMTargetMachine TargetPassConfig *createPassConfig(PassManagerBase &PM) override; diff --git a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp --- a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp +++ b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp @@ -160,13 +160,46 @@ getEffectiveRelocModel(RM), getEffectiveSystemZCodeModel(CM, getEffectiveRelocModel(RM), JIT), OL), - TLOF(std::make_unique()), - Subtarget(TT, std::string(CPU), std::string(FS), *this) { + TLOF(std::make_unique()) { initAsmInfo(); } SystemZTargetMachine::~SystemZTargetMachine() = default; +const SystemZSubtarget * +SystemZTargetMachine::getSubtargetImpl(const Function &F) const { + Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute FSAttr = F.getFnAttribute("target-features"); + + std::string CPU = !CPUAttr.hasAttribute(Attribute::None) + ? CPUAttr.getValueAsString().str() + : TargetCPU; + std::string FS = !FSAttr.hasAttribute(Attribute::None) + ? FSAttr.getValueAsString().str() + : TargetFS; + + // FIXME: This is related to the code below to reset the target options, + // we need to know whether or not the soft float flag is set on the + // function, so we can enable it as a subtarget feature. + bool softFloat = + F.hasFnAttribute("use-soft-float") && + F.getFnAttribute("use-soft-float").getValueAsString() == "true"; + + if (softFloat) + FS += FS.empty() ? "+soft-float" : ",+soft-float"; + + auto &I = SubtargetMap[CPU + FS]; + if (!I) { + // 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 + // function that reside in TargetOptions. + resetTargetOptions(F); + I = std::make_unique(TargetTriple, CPU, FS, *this); + } + + return I.get(); +} + namespace { /// SystemZ Code Generator Pass Configuration Options. @@ -199,8 +232,7 @@ void SystemZPassConfig::addIRPasses() { if (getOptLevel() != CodeGenOpt::None) { - if (!getTM().getSubtargetImpl()->hasSoftFloat()) - addPass(createSystemZTDCPass()); + addPass(createSystemZTDCPass()); addPass(createLoopDataPrefetchPass()); } diff --git a/llvm/test/CodeGen/SystemZ/function-attributes-01.ll b/llvm/test/CodeGen/SystemZ/function-attributes-01.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/function-attributes-01.ll @@ -0,0 +1,125 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu \ +; RUN: | FileCheck %s --check-prefixes=CHECK,DEFAULT +; RUN: llc < %s -mtriple=s390x-linux-gnu -mattr=soft-float \ +; RUN: | FileCheck %s --check-prefixes=CHECK,SOFT-FLOAT +; RUN: llc < %s -mtriple=s390x-linux-gnu -mattr=-soft-float \ +; RUN: | FileCheck %s --check-prefixes=CHECK,NO-SOFT-FL +; RUN: llc < %s -mtriple=s390x-linux-gnu -mattr=-vector \ +; RUN: | FileCheck %s --check-prefixes=CHECK,NO-VECTOR +; +; Test per function attributes and command line arguments that override them. + +attributes #1 = { "target-cpu"="z14" "target-features"="+vector" "use-soft-float"="false" } +define double @fun1(double* %A) #1 { +; CHECK-LABEL: fun1: +; DEFAULT: ld %f0, 0(%r2) +; SOFT-FLOAT: lg %r2, 0(%r2) +; NO-SOFT-FL: ld %f0, 0(%r2) +; NO-VECTOR: ld %f0, 0(%r2) +; CHECK-NEXT: br %r14 +entry: + %0 = load double, double* %A + ret double %0 +} + +attributes #2 = { "target-cpu"="z14" "target-features"="+vector" "use-soft-float"="true" } +define double @fun2(double* %A) #2 { +; CHECK-LABEL: fun2: +; DEFAULT: lg %r2, 0(%r2) +; SOFT-FLOAT: lg %r2, 0(%r2) +; NO-SOFT-FL: lg %r2, 0(%r2) +; NO-VECTOR: lg %r2, 0(%r2) +; CHECK-NEXT: br %r14 +entry: + %0 = load double, double* %A + ret double %0 +} + +attributes #3 = { "target-cpu"="z14" "target-features"="+vector" "use-soft-float"="false" } +define <2 x double> @fun3(<2 x double>* %A) #3 { +; CHECK-LABEL: fun3: +; DEFAULT: vl %v24, 0(%r2), 4 +; SOFT-FLOAT: lg %r0, 0(%r2) +; SOFT-FLOAT-NEXT: lg %r3, 8(%r2) +; SOFT-FLOAT-NEXT: lgr %r2, %r0 +; NO-SOFT-FL: vl %v24, 0(%r2), 4 +; NO-VECTOR: ld %f0, 0(%r2) +; NO-VECTOR-NEXT: ld %f2, 8(%r2) +; CHECK-NEXT: br %r14 +entry: + %0 = load <2 x double>, <2 x double>* %A + ret <2 x double> %0 +} + +attributes #4 = { "target-cpu"="z14" "target-features"="+vector" "use-soft-float"="true" } +define <2 x double> @fun4(<2 x double>* %A) #4 { +; CHECK-LABEL: fun4: +; DEFAULT: lg %r0, 0(%r2) +; DEFAULT-NEXT: lg %r3, 8(%r2) +; DEFAULT-NEXT: lgr %r2, %r0 +; SOFT-FLOAT: lg %r0, 0(%r2) +; SOFT-FLOAT-NEXT: lg %r3, 8(%r2) +; SOFT-FLOAT-NEXT: lgr %r2, %r0 +; NO-SOFT-FL: lg %r0, 0(%r2) +; NO-SOFT-FL-NEXT: lg %r3, 8(%r2) +; NO-SOFT-FL-NEXT: lgr %r2, %r0 +; NO-VECTOR: lg %r0, 0(%r2) +; NO-VECTOR-NEXT: lg %r3, 8(%r2) +; NO-VECTOR-NEXT: lgr %r2, %r0 +; CHECK-NEXT: br %r14 +entry: + %0 = load <2 x double>, <2 x double>* %A + ret <2 x double> %0 +} + +attributes #5 = { "target-cpu"="z14" "target-features"="-vector" "use-soft-float"="false" } +define <2 x double> @fun5(<2 x double>* %A) #5 { +; CHECK-LABEL: fun5: +; DEFAULT: ld %f0, 0(%r2) +; DEFAULT-NEXT: ld %f2, 8(%r2) +; SOFT-FLOAT: lg %r0, 0(%r2) +; SOFT-FLOAT-NEXT: lg %r3, 8(%r2) +; SOFT-FLOAT-NEXT: lgr %r2, %r0 +; NO-SOFT-FL: ld %f0, 0(%r2) +; NO-SOFT-FL-NEXT: ld %f2, 8(%r2) +; NO-VECTOR: ld %f0, 0(%r2) +; NO-VECTOR-NEXT: ld %f2, 8(%r2) +; CHECK-NEXT: br %r14 +entry: + %0 = load <2 x double>, <2 x double>* %A + ret <2 x double> %0 +} + +attributes #6 = { "target-cpu"="zEC12" "use-soft-float"="false" } +define <2 x double> @fun6(<2 x double>* %A) #6 { +; CHECK-LABEL: fun6: +; DEFAULT: ld %f0, 0(%r2) +; DEFAULT-NEXT: ld %f2, 8(%r2) +; SOFT-FLOAT: lg %r0, 0(%r2) +; SOFT-FLOAT-NEXT: lg %r3, 8(%r2) +; SOFT-FLOAT-NEXT: lgr %r2, %r0 +; NO-SOFT-FL: ld %f0, 0(%r2) +; NO-SOFT-FL-NEXT: ld %f2, 8(%r2) +; NO-VECTOR: ld %f0, 0(%r2) +; NO-VECTOR-NEXT: ld %f2, 8(%r2) +; CHECK-NEXT: br %r14 +entry: + %0 = load <2 x double>, <2 x double>* %A + ret <2 x double> %0 +} + +attributes #7 = { "target-cpu"="zEC12" "target-features"="+vector" "use-soft-float"="false" } +define <2 x double> @fun7(<2 x double>* %A) #7 { +; CHECK-LABEL: fun7: +; DEFAULT: vl %v24, 0(%r2), 4 +; SOFT-FLOAT: lg %r0, 0(%r2) +; SOFT-FLOAT-NEXT: lg %r3, 8(%r2) +; SOFT-FLOAT-NEXT: lgr %r2, %r0 +; NO-SOFT-FL: vl %v24, 0(%r2), 4 +; NO-VECTOR: ld %f0, 0(%r2) +; NO-VECTOR-NEXT: ld %f2, 8(%r2) +; CHECK-NEXT: br %r14 +entry: + %0 = load <2 x double>, <2 x double>* %A + ret <2 x double> %0 +}