1 | //===- GISelMITest.h --------------------------------------------*- C++ -*-===// |
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 | #ifndef LLVM_UNITTEST_CODEGEN_GLOBALISEL_GISELMI_H |
9 | #define LLVM_UNITTEST_CODEGEN_GLOBALISEL_GISELMI_H |
10 | |
11 | #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" |
12 | #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" |
13 | #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" |
14 | #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" |
15 | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" |
16 | #include "llvm/CodeGen/GlobalISel/Utils.h" |
17 | #include "llvm/CodeGen/MIRParser/MIRParser.h" |
18 | #include "llvm/CodeGen/MachineFunction.h" |
19 | #include "llvm/CodeGen/MachineModuleInfo.h" |
20 | #include "llvm/CodeGen/TargetFrameLowering.h" |
21 | #include "llvm/CodeGen/TargetInstrInfo.h" |
22 | #include "llvm/CodeGen/TargetLowering.h" |
23 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
24 | #include "llvm/FileCheck/FileCheck.h" |
25 | #include "llvm/InitializePasses.h" |
26 | #include "llvm/MC/TargetRegistry.h" |
27 | #include "llvm/Support/SourceMgr.h" |
28 | #include "llvm/Support/TargetSelect.h" |
29 | #include "llvm/Target/TargetMachine.h" |
30 | #include "llvm/Target/TargetOptions.h" |
31 | #include "gtest/gtest.h" |
32 | |
33 | using namespace llvm; |
34 | using namespace MIPatternMatch; |
35 | |
36 | static inline void initLLVM() { |
37 | InitializeAllTargets(); |
38 | InitializeAllTargetMCs(); |
39 | InitializeAllAsmPrinters(); |
40 | InitializeAllAsmParsers(); |
41 | |
42 | PassRegistry *Registry = PassRegistry::getPassRegistry(); |
43 | initializeCore(*Registry); |
44 | initializeCodeGen(*Registry); |
45 | } |
46 | |
47 | // Define a printers to help debugging when things go wrong. |
48 | namespace llvm { |
49 | std::ostream & |
50 | operator<<(std::ostream &OS, const LLT Ty); |
51 | |
52 | std::ostream & |
53 | operator<<(std::ostream &OS, const MachineFunction &MF); |
54 | } |
55 | |
56 | static std::unique_ptr<Module> parseMIR(LLVMContext &Context, |
57 | std::unique_ptr<MIRParser> &MIR, |
58 | const TargetMachine &TM, |
59 | StringRef MIRCode, const char *FuncName, |
60 | MachineModuleInfo &MMI) { |
61 | SMDiagnostic Diagnostic; |
62 | std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(InputData: MIRCode); |
63 | MIR = createMIRParser(Contents: std::move(MBuffer), Context); |
64 | if (!MIR) |
65 | return nullptr; |
66 | |
67 | std::unique_ptr<Module> M = MIR->parseIRModule(); |
68 | if (!M) |
69 | return nullptr; |
70 | |
71 | M->setDataLayout(TM.createDataLayout()); |
72 | |
73 | if (MIR->parseMachineFunctions(M&: *M, MMI)) |
74 | return nullptr; |
75 | |
76 | return M; |
77 | } |
78 | static std::pair<std::unique_ptr<Module>, std::unique_ptr<MachineModuleInfo>> |
79 | createDummyModule(LLVMContext &Context, const LLVMTargetMachine &TM, |
80 | StringRef MIRString, const char *FuncName) { |
81 | std::unique_ptr<MIRParser> MIR; |
82 | auto MMI = std::make_unique<MachineModuleInfo>(args: &TM); |
83 | std::unique_ptr<Module> M = |
84 | parseMIR(Context, MIR, TM, MIRCode: MIRString, FuncName, MMI&: *MMI); |
85 | return make_pair(x: std::move(M), y: std::move(MMI)); |
86 | } |
87 | |
88 | static MachineFunction *getMFFromMMI(const Module *M, |
89 | const MachineModuleInfo *MMI) { |
90 | Function *F = M->getFunction(Name: "func" ); |
91 | auto *MF = MMI->getMachineFunction(F: *F); |
92 | return MF; |
93 | } |
94 | |
95 | static void collectCopies(SmallVectorImpl<Register> &Copies, |
96 | MachineFunction *MF) { |
97 | for (auto &MBB : *MF) |
98 | for (MachineInstr &MI : MBB) { |
99 | if (MI.getOpcode() == TargetOpcode::COPY) |
100 | Copies.push_back(Elt: MI.getOperand(i: 0).getReg()); |
101 | } |
102 | } |
103 | |
104 | class GISelMITest : public ::testing::Test { |
105 | protected: |
106 | GISelMITest() : ::testing::Test() {} |
107 | |
108 | /// Prepare a target specific LLVMTargetMachine. |
109 | virtual std::unique_ptr<LLVMTargetMachine> createTargetMachine() const = 0; |
110 | |
111 | /// Get the stub sample MIR test function. |
112 | virtual void getTargetTestModuleString(SmallString<512> &S, |
113 | StringRef MIRFunc) const = 0; |
114 | |
115 | void setUp(StringRef = "" ) { |
116 | TM = createTargetMachine(); |
117 | if (!TM) |
118 | return; |
119 | |
120 | SmallString<512> MIRString; |
121 | getTargetTestModuleString(S&: MIRString, MIRFunc: ExtraAssembly); |
122 | |
123 | ModuleMMIPair = createDummyModule(Context, TM: *TM, MIRString, FuncName: "func" ); |
124 | MF = getMFFromMMI(M: ModuleMMIPair.first.get(), MMI: ModuleMMIPair.second.get()); |
125 | collectCopies(Copies, MF); |
126 | EntryMBB = &*MF->begin(); |
127 | B.setMF(*MF); |
128 | MRI = &MF->getRegInfo(); |
129 | B.setInsertPt(MBB&: *EntryMBB, II: EntryMBB->end()); |
130 | } |
131 | |
132 | LLVMContext Context; |
133 | std::unique_ptr<LLVMTargetMachine> TM; |
134 | MachineFunction *MF; |
135 | std::pair<std::unique_ptr<Module>, std::unique_ptr<MachineModuleInfo>> |
136 | ModuleMMIPair; |
137 | SmallVector<Register, 4> Copies; |
138 | MachineBasicBlock *EntryMBB; |
139 | MachineIRBuilder B; |
140 | MachineRegisterInfo *MRI; |
141 | }; |
142 | |
143 | class AArch64GISelMITest : public GISelMITest { |
144 | std::unique_ptr<LLVMTargetMachine> createTargetMachine() const override; |
145 | void getTargetTestModuleString(SmallString<512> &S, |
146 | StringRef MIRFunc) const override; |
147 | }; |
148 | |
149 | class AMDGPUGISelMITest : public GISelMITest { |
150 | std::unique_ptr<LLVMTargetMachine> createTargetMachine() const override; |
151 | void getTargetTestModuleString(SmallString<512> &S, |
152 | StringRef MIRFunc) const override; |
153 | }; |
154 | |
155 | #define DefineLegalizerInfo(Name, SettingUpActionsBlock) \ |
156 | class Name##Info : public LegalizerInfo { \ |
157 | public: \ |
158 | Name##Info(const TargetSubtargetInfo &ST) { \ |
159 | using namespace TargetOpcode; \ |
160 | const LLT s8 = LLT::scalar(8); \ |
161 | (void)s8; \ |
162 | const LLT s16 = LLT::scalar(16); \ |
163 | (void)s16; \ |
164 | const LLT s32 = LLT::scalar(32); \ |
165 | (void)s32; \ |
166 | const LLT s64 = LLT::scalar(64); \ |
167 | (void)s64; \ |
168 | const LLT s128 = LLT::scalar(128); \ |
169 | (void)s128; \ |
170 | do \ |
171 | SettingUpActionsBlock while (0); \ |
172 | getLegacyLegalizerInfo().computeTables(); \ |
173 | verify(*ST.getInstrInfo()); \ |
174 | } \ |
175 | }; |
176 | |
177 | static inline bool CheckMachineFunction(const MachineFunction &MF, |
178 | StringRef CheckStr) { |
179 | SmallString<512> Msg; |
180 | raw_svector_ostream OS(Msg); |
181 | MF.print(OS); |
182 | auto OutputBuf = MemoryBuffer::getMemBuffer(InputData: Msg, BufferName: "Output" , RequiresNullTerminator: false); |
183 | auto CheckBuf = MemoryBuffer::getMemBuffer(InputData: CheckStr, BufferName: "" ); |
184 | SmallString<4096> CheckFileBuffer; |
185 | FileCheckRequest Req; |
186 | FileCheck FC(Req); |
187 | StringRef CheckFileText = |
188 | FC.CanonicalizeFile(MB&: *CheckBuf.get(), OutputBuffer&: CheckFileBuffer); |
189 | SourceMgr SM; |
190 | SM.AddNewSourceBuffer(F: MemoryBuffer::getMemBuffer(InputData: CheckFileText, BufferName: "CheckFile" ), |
191 | IncludeLoc: SMLoc()); |
192 | if (FC.readCheckFile(SM, Buffer: CheckFileText)) |
193 | return false; |
194 | |
195 | auto OutBuffer = OutputBuf->getBuffer(); |
196 | SM.AddNewSourceBuffer(F: std::move(OutputBuf), IncludeLoc: SMLoc()); |
197 | return FC.checkInput(SM, Buffer: OutBuffer); |
198 | } |
199 | #endif |
200 | |