1349cc55cSDimitry Andric //===-- R600TargetMachine.cpp - TargetMachine for hw codegen targets-------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric /// \file
10349cc55cSDimitry Andric /// The AMDGPU-R600 target machine contains all of the hardware specific
11349cc55cSDimitry Andric /// information  needed to emit code for R600 GPUs.
12349cc55cSDimitry Andric //
13349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
14349cc55cSDimitry Andric 
15349cc55cSDimitry Andric #include "R600TargetMachine.h"
16349cc55cSDimitry Andric #include "AMDGPUTargetMachine.h"
17349cc55cSDimitry Andric #include "R600.h"
18349cc55cSDimitry Andric #include "R600MachineScheduler.h"
19349cc55cSDimitry Andric #include "R600TargetTransformInfo.h"
20349cc55cSDimitry Andric #include "llvm/Transforms/Scalar.h"
21bdd1243dSDimitry Andric #include <optional>
22349cc55cSDimitry Andric 
23349cc55cSDimitry Andric using namespace llvm;
24349cc55cSDimitry Andric 
25349cc55cSDimitry Andric static cl::opt<bool>
26349cc55cSDimitry Andric     EnableR600StructurizeCFG("r600-ir-structurize",
27349cc55cSDimitry Andric                              cl::desc("Use StructurizeCFG IR pass"),
28349cc55cSDimitry Andric                              cl::init(true));
29349cc55cSDimitry Andric 
30349cc55cSDimitry Andric static cl::opt<bool> EnableR600IfConvert("r600-if-convert",
31349cc55cSDimitry Andric                                          cl::desc("Use if conversion pass"),
32349cc55cSDimitry Andric                                          cl::ReallyHidden, cl::init(true));
33349cc55cSDimitry Andric 
34349cc55cSDimitry Andric static cl::opt<bool, true> EnableAMDGPUFunctionCallsOpt(
35349cc55cSDimitry Andric     "amdgpu-function-calls", cl::desc("Enable AMDGPU function call support"),
36349cc55cSDimitry Andric     cl::location(AMDGPUTargetMachine::EnableFunctionCalls), cl::init(true),
37349cc55cSDimitry Andric     cl::Hidden);
38349cc55cSDimitry Andric 
createR600MachineScheduler(MachineSchedContext * C)39349cc55cSDimitry Andric static ScheduleDAGInstrs *createR600MachineScheduler(MachineSchedContext *C) {
40349cc55cSDimitry Andric   return new ScheduleDAGMILive(C, std::make_unique<R600SchedStrategy>());
41349cc55cSDimitry Andric }
42349cc55cSDimitry Andric 
43349cc55cSDimitry Andric static MachineSchedRegistry R600SchedRegistry("r600",
44349cc55cSDimitry Andric                                               "Run R600's custom scheduler",
45349cc55cSDimitry Andric                                               createR600MachineScheduler);
46349cc55cSDimitry Andric 
47349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
48349cc55cSDimitry Andric // R600 Target Machine (R600 -> Cayman)
49349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
50349cc55cSDimitry Andric 
R600TargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,TargetOptions Options,std::optional<Reloc::Model> RM,std::optional<CodeModel::Model> CM,CodeGenOptLevel OL,bool JIT)51349cc55cSDimitry Andric R600TargetMachine::R600TargetMachine(const Target &T, const Triple &TT,
52349cc55cSDimitry Andric                                      StringRef CPU, StringRef FS,
53349cc55cSDimitry Andric                                      TargetOptions Options,
54bdd1243dSDimitry Andric                                      std::optional<Reloc::Model> RM,
55bdd1243dSDimitry Andric                                      std::optional<CodeModel::Model> CM,
56*5f757f3fSDimitry Andric                                      CodeGenOptLevel OL, bool JIT)
57349cc55cSDimitry Andric     : AMDGPUTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL) {
58349cc55cSDimitry Andric   setRequiresStructuredCFG(true);
59349cc55cSDimitry Andric 
60349cc55cSDimitry Andric   // Override the default since calls aren't supported for r600.
61349cc55cSDimitry Andric   if (EnableFunctionCalls &&
62349cc55cSDimitry Andric       EnableAMDGPUFunctionCallsOpt.getNumOccurrences() == 0)
63349cc55cSDimitry Andric     EnableFunctionCalls = false;
64349cc55cSDimitry Andric }
65349cc55cSDimitry Andric 
66349cc55cSDimitry Andric const TargetSubtargetInfo *
getSubtargetImpl(const Function & F) const67349cc55cSDimitry Andric R600TargetMachine::getSubtargetImpl(const Function &F) const {
68349cc55cSDimitry Andric   StringRef GPU = getGPUName(F);
69349cc55cSDimitry Andric   StringRef FS = getFeatureString(F);
70349cc55cSDimitry Andric 
71349cc55cSDimitry Andric   SmallString<128> SubtargetKey(GPU);
72349cc55cSDimitry Andric   SubtargetKey.append(FS);
73349cc55cSDimitry Andric 
74349cc55cSDimitry Andric   auto &I = SubtargetMap[SubtargetKey];
75349cc55cSDimitry Andric   if (!I) {
76349cc55cSDimitry Andric     // This needs to be done before we create a new subtarget since any
77349cc55cSDimitry Andric     // creation will depend on the TM and the code generation flags on the
78349cc55cSDimitry Andric     // function that reside in TargetOptions.
79349cc55cSDimitry Andric     resetTargetOptions(F);
80349cc55cSDimitry Andric     I = std::make_unique<R600Subtarget>(TargetTriple, GPU, FS, *this);
81349cc55cSDimitry Andric   }
82349cc55cSDimitry Andric 
83349cc55cSDimitry Andric   return I.get();
84349cc55cSDimitry Andric }
85349cc55cSDimitry Andric 
86349cc55cSDimitry Andric TargetTransformInfo
getTargetTransformInfo(const Function & F) const8781ad6265SDimitry Andric R600TargetMachine::getTargetTransformInfo(const Function &F) const {
88349cc55cSDimitry Andric   return TargetTransformInfo(R600TTIImpl(this, F));
89349cc55cSDimitry Andric }
90349cc55cSDimitry Andric 
91bdd1243dSDimitry Andric namespace {
92349cc55cSDimitry Andric class R600PassConfig final : public AMDGPUPassConfig {
93349cc55cSDimitry Andric public:
R600PassConfig(LLVMTargetMachine & TM,PassManagerBase & PM)94349cc55cSDimitry Andric   R600PassConfig(LLVMTargetMachine &TM, PassManagerBase &PM)
95349cc55cSDimitry Andric       : AMDGPUPassConfig(TM, PM) {}
96349cc55cSDimitry Andric 
97349cc55cSDimitry Andric   ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext * C) const98349cc55cSDimitry Andric   createMachineScheduler(MachineSchedContext *C) const override {
99349cc55cSDimitry Andric     return createR600MachineScheduler(C);
100349cc55cSDimitry Andric   }
101349cc55cSDimitry Andric 
102349cc55cSDimitry Andric   bool addPreISel() override;
103349cc55cSDimitry Andric   bool addInstSelector() override;
104349cc55cSDimitry Andric   void addPreRegAlloc() override;
105349cc55cSDimitry Andric   void addPreSched2() override;
106349cc55cSDimitry Andric   void addPreEmitPass() override;
107349cc55cSDimitry Andric };
108bdd1243dSDimitry Andric } // namespace
109349cc55cSDimitry Andric 
110349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
111349cc55cSDimitry Andric // R600 Pass Setup
112349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
113349cc55cSDimitry Andric 
addPreISel()114349cc55cSDimitry Andric bool R600PassConfig::addPreISel() {
115349cc55cSDimitry Andric   AMDGPUPassConfig::addPreISel();
116349cc55cSDimitry Andric 
117349cc55cSDimitry Andric   if (EnableR600StructurizeCFG)
118349cc55cSDimitry Andric     addPass(createStructurizeCFGPass());
119349cc55cSDimitry Andric   return false;
120349cc55cSDimitry Andric }
121349cc55cSDimitry Andric 
addInstSelector()122349cc55cSDimitry Andric bool R600PassConfig::addInstSelector() {
123bdd1243dSDimitry Andric   addPass(createR600ISelDag(getAMDGPUTargetMachine(), getOptLevel()));
124349cc55cSDimitry Andric   return false;
125349cc55cSDimitry Andric }
126349cc55cSDimitry Andric 
addPreRegAlloc()127349cc55cSDimitry Andric void R600PassConfig::addPreRegAlloc() { addPass(createR600VectorRegMerger()); }
128349cc55cSDimitry Andric 
addPreSched2()129349cc55cSDimitry Andric void R600PassConfig::addPreSched2() {
130349cc55cSDimitry Andric   addPass(createR600EmitClauseMarkers());
131349cc55cSDimitry Andric   if (EnableR600IfConvert)
132349cc55cSDimitry Andric     addPass(&IfConverterID);
133349cc55cSDimitry Andric   addPass(createR600ClauseMergePass());
134349cc55cSDimitry Andric }
135349cc55cSDimitry Andric 
addPreEmitPass()136349cc55cSDimitry Andric void R600PassConfig::addPreEmitPass() {
13781ad6265SDimitry Andric   addPass(createR600MachineCFGStructurizerPass());
138349cc55cSDimitry Andric   addPass(createR600ExpandSpecialInstrsPass());
139349cc55cSDimitry Andric   addPass(&FinalizeMachineBundlesID);
140349cc55cSDimitry Andric   addPass(createR600Packetizer());
141349cc55cSDimitry Andric   addPass(createR600ControlFlowFinalizer());
142349cc55cSDimitry Andric }
143349cc55cSDimitry Andric 
createPassConfig(PassManagerBase & PM)144349cc55cSDimitry Andric TargetPassConfig *R600TargetMachine::createPassConfig(PassManagerBase &PM) {
145349cc55cSDimitry Andric   return new R600PassConfig(*this, PM);
146349cc55cSDimitry Andric }
147