1 //===-- R600TargetMachine.cpp - TargetMachine for hw codegen targets-------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file
10 /// The AMDGPU-R600 target machine contains all of the hardware specific
11 /// information  needed to emit code for R600 GPUs.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "R600TargetMachine.h"
16 #include "AMDGPUTargetMachine.h"
17 #include "R600.h"
18 #include "R600MachineScheduler.h"
19 #include "R600TargetTransformInfo.h"
20 #include "llvm/Transforms/Scalar.h"
21 #include <optional>
22 
23 using namespace llvm;
24 
25 static cl::opt<bool>
26     EnableR600StructurizeCFG("r600-ir-structurize",
27                              cl::desc("Use StructurizeCFG IR pass"),
28                              cl::init(true));
29 
30 static cl::opt<bool> EnableR600IfConvert("r600-if-convert",
31                                          cl::desc("Use if conversion pass"),
32                                          cl::ReallyHidden, cl::init(true));
33 
34 static cl::opt<bool, true> EnableAMDGPUFunctionCallsOpt(
35     "amdgpu-function-calls", cl::desc("Enable AMDGPU function call support"),
36     cl::location(AMDGPUTargetMachine::EnableFunctionCalls), cl::init(true),
37     cl::Hidden);
38 
39 static ScheduleDAGInstrs *createR600MachineScheduler(MachineSchedContext *C) {
40   return new ScheduleDAGMILive(C, std::make_unique<R600SchedStrategy>());
41 }
42 
43 static MachineSchedRegistry R600SchedRegistry("r600",
44                                               "Run R600's custom scheduler",
45                                               createR600MachineScheduler);
46 
47 //===----------------------------------------------------------------------===//
48 // R600 Target Machine (R600 -> Cayman)
49 //===----------------------------------------------------------------------===//
50 
51 R600TargetMachine::R600TargetMachine(const Target &T, const Triple &TT,
52                                      StringRef CPU, StringRef FS,
53                                      TargetOptions Options,
54                                      std::optional<Reloc::Model> RM,
55                                      std::optional<CodeModel::Model> CM,
56                                      CodeGenOpt::Level OL, bool JIT)
57     : AMDGPUTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL) {
58   setRequiresStructuredCFG(true);
59 
60   // Override the default since calls aren't supported for r600.
61   if (EnableFunctionCalls &&
62       EnableAMDGPUFunctionCallsOpt.getNumOccurrences() == 0)
63     EnableFunctionCalls = false;
64 }
65 
66 const TargetSubtargetInfo *
67 R600TargetMachine::getSubtargetImpl(const Function &F) const {
68   StringRef GPU = getGPUName(F);
69   StringRef FS = getFeatureString(F);
70 
71   SmallString<128> SubtargetKey(GPU);
72   SubtargetKey.append(FS);
73 
74   auto &I = SubtargetMap[SubtargetKey];
75   if (!I) {
76     // This needs to be done before we create a new subtarget since any
77     // creation will depend on the TM and the code generation flags on the
78     // function that reside in TargetOptions.
79     resetTargetOptions(F);
80     I = std::make_unique<R600Subtarget>(TargetTriple, GPU, FS, *this);
81   }
82 
83   return I.get();
84 }
85 
86 TargetTransformInfo
87 R600TargetMachine::getTargetTransformInfo(const Function &F) const {
88   return TargetTransformInfo(R600TTIImpl(this, F));
89 }
90 
91 namespace {
92 class R600PassConfig final : public AMDGPUPassConfig {
93 public:
94   R600PassConfig(LLVMTargetMachine &TM, PassManagerBase &PM)
95       : AMDGPUPassConfig(TM, PM) {}
96 
97   ScheduleDAGInstrs *
98   createMachineScheduler(MachineSchedContext *C) const override {
99     return createR600MachineScheduler(C);
100   }
101 
102   bool addPreISel() override;
103   bool addInstSelector() override;
104   void addPreRegAlloc() override;
105   void addPreSched2() override;
106   void addPreEmitPass() override;
107 };
108 } // namespace
109 
110 //===----------------------------------------------------------------------===//
111 // R600 Pass Setup
112 //===----------------------------------------------------------------------===//
113 
114 bool R600PassConfig::addPreISel() {
115   AMDGPUPassConfig::addPreISel();
116 
117   if (EnableR600StructurizeCFG)
118     addPass(createStructurizeCFGPass());
119   return false;
120 }
121 
122 bool R600PassConfig::addInstSelector() {
123   addPass(createR600ISelDag(getAMDGPUTargetMachine(), getOptLevel()));
124   return false;
125 }
126 
127 void R600PassConfig::addPreRegAlloc() { addPass(createR600VectorRegMerger()); }
128 
129 void R600PassConfig::addPreSched2() {
130   addPass(createR600EmitClauseMarkers());
131   if (EnableR600IfConvert)
132     addPass(&IfConverterID);
133   addPass(createR600ClauseMergePass());
134 }
135 
136 void R600PassConfig::addPreEmitPass() {
137   addPass(createR600MachineCFGStructurizerPass());
138   addPass(createR600ExpandSpecialInstrsPass());
139   addPass(&FinalizeMachineBundlesID);
140   addPass(createR600Packetizer());
141   addPass(createR600ControlFlowFinalizer());
142 }
143 
144 TargetPassConfig *R600TargetMachine::createPassConfig(PassManagerBase &PM) {
145   return new R600PassConfig(*this, PM);
146 }
147