1 //===------- JITLinkTestCommon.cpp - Common code for JITLink tests --------===//
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 #include "JITLinkTestCommon.h"
10 #include "llvm/MC/MCCodeEmitter.h"
11 #include "llvm/MC/MCObjectWriter.h"
12 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
13 #include "llvm/Support/TargetSelect.h"
14 
15 using namespace llvm::jitlink;
16 namespace llvm {
17 
18 Expected<std::unique_ptr<JITLinkTestCommon::TestResources>>
Create(StringRef AsmSrc,StringRef TripleStr,bool PIC,bool LargeCodeModel,MCTargetOptions Options)19 JITLinkTestCommon::TestResources::Create(StringRef AsmSrc, StringRef TripleStr,
20                                          bool PIC, bool LargeCodeModel,
21                                          MCTargetOptions Options) {
22   Error Err = Error::success();
23   auto R = std::unique_ptr<TestResources>(new TestResources(
24       AsmSrc, TripleStr, PIC, LargeCodeModel, std::move(Options), Err));
25   if (Err)
26     return std::move(Err);
27   return std::move(R);
28 }
29 
30 MemoryBufferRef
getTestObjectBufferRef() const31 JITLinkTestCommon::TestResources::getTestObjectBufferRef() const {
32   return MemoryBufferRef(StringRef(ObjBuffer.data(), ObjBuffer.size()),
33                          "Test object");
34 }
35 
TestResources(StringRef AsmSrc,StringRef TripleStr,bool PIC,bool LargeCodeModel,MCTargetOptions Options,Error & Err)36 JITLinkTestCommon::TestResources::TestResources(StringRef AsmSrc,
37                                                 StringRef TripleStr, bool PIC,
38                                                 bool LargeCodeModel,
39                                                 MCTargetOptions Options,
40                                                 Error &Err)
41     : ObjStream(ObjBuffer), Options(std::move(Options)) {
42   ErrorAsOutParameter _(&Err);
43   Triple TT(Triple::normalize(TripleStr));
44   if (auto Err2 = initializeTripleSpecifics(TT)) {
45     Err = std::move(Err2);
46     return;
47   }
48   initializeTestSpecifics(AsmSrc, TT, PIC, LargeCodeModel);
49 }
50 
initializeTripleSpecifics(Triple & TT)51 Error JITLinkTestCommon::TestResources::initializeTripleSpecifics(Triple &TT) {
52   std::string ErrorMsg;
53   TheTarget = TargetRegistry::lookupTarget("", TT, ErrorMsg);
54 
55   if (!TheTarget)
56     return make_error<StringError>(ErrorMsg, inconvertibleErrorCode());
57 
58   MRI.reset(TheTarget->createMCRegInfo(TT.getTriple()));
59   if (!MRI)
60     report_fatal_error("Could not build MCRegisterInfo for triple");
61 
62   MAI.reset(TheTarget->createMCAsmInfo(*MRI, TT.getTriple()));
63   if (!MAI)
64     report_fatal_error("Could not build MCAsmInfo for triple");
65 
66   MCII.reset(TheTarget->createMCInstrInfo());
67   if (!MCII)
68     report_fatal_error("Could not build MCInstrInfo for triple");
69 
70   STI.reset(TheTarget->createMCSubtargetInfo(TT.getTriple(), "", ""));
71   if (!STI)
72     report_fatal_error("Could not build MCSubtargetInfo for triple");
73 
74   DisCtx = llvm::make_unique<MCContext>(MAI.get(), MRI.get(), nullptr);
75   Dis.reset(TheTarget->createMCDisassembler(*STI, *DisCtx));
76 
77   if (!Dis)
78     report_fatal_error("Could not build MCDisassembler");
79 
80   return Error::success();
81 }
82 
initializeTestSpecifics(StringRef AsmSrc,const Triple & TT,bool PIC,bool LargeCodeModel)83 void JITLinkTestCommon::TestResources::initializeTestSpecifics(
84     StringRef AsmSrc, const Triple &TT, bool PIC, bool LargeCodeModel) {
85   SrcMgr.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(AsmSrc), SMLoc());
86   AsCtx = llvm::make_unique<MCContext>(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
87   MOFI.InitMCObjectFileInfo(TT, PIC, *AsCtx, LargeCodeModel);
88 
89   std::unique_ptr<MCCodeEmitter> CE(
90       TheTarget->createMCCodeEmitter(*MCII, *MRI, *AsCtx));
91   if (!CE)
92     report_fatal_error("Could not build MCCodeEmitter");
93 
94   std::unique_ptr<MCAsmBackend> MAB(
95       TheTarget->createMCAsmBackend(*STI, *MRI, Options));
96   if (!MAB)
97     report_fatal_error("Could not build MCAsmBackend for test");
98 
99   std::unique_ptr<MCObjectWriter> MOW(MAB->createObjectWriter(ObjStream));
100 
101   MOS.reset(TheTarget->createMCObjectStreamer(
102       TT, *AsCtx, std::move(MAB), std::move(MOW), std::move(CE), *STI,
103       Options.MCRelaxAll, Options.MCIncrementalLinkerCompatible, false));
104 
105   std::unique_ptr<MCAsmParser> MAP(
106       createMCAsmParser(SrcMgr, *AsCtx, *MOS, *MAI));
107   std::unique_ptr<MCTargetAsmParser> TAP(
108       TheTarget->createMCAsmParser(*STI, *MAP, *MCII, Options));
109 
110   if (!TAP)
111     report_fatal_error("Could not build MCTargetAsmParser for test");
112 
113   MAP->setTargetParser(*TAP);
114 
115   if (MAP->Run(false))
116     report_fatal_error("Failed to parse test case");
117 }
118 
TestJITLinkContext(TestResources & TR,TestCaseFunction TestCase)119 JITLinkTestCommon::TestJITLinkContext::TestJITLinkContext(
120     TestResources &TR, TestCaseFunction TestCase)
121     : TR(TR), TestCase(std::move(TestCase)) {}
122 
123 JITLinkTestCommon::TestJITLinkContext &
setMemoryManager(std::unique_ptr<JITLinkMemoryManager> MM)124 JITLinkTestCommon::TestJITLinkContext::setMemoryManager(
125     std::unique_ptr<JITLinkMemoryManager> MM) {
126   assert(!MemMgr && "Memory manager already set");
127   MemMgr = std::move(MM);
128   return *this;
129 }
130 
131 JITLinkMemoryManager &
getMemoryManager()132 JITLinkTestCommon::TestJITLinkContext::getMemoryManager() {
133   if (!MemMgr)
134     MemMgr = llvm::make_unique<InProcessMemoryManager>();
135   return *MemMgr;
136 }
137 
getObjectBuffer() const138 MemoryBufferRef JITLinkTestCommon::TestJITLinkContext::getObjectBuffer() const {
139   return TR.getTestObjectBufferRef();
140 }
141 
notifyFailed(Error Err)142 void JITLinkTestCommon::TestJITLinkContext::notifyFailed(Error Err) {
143   ADD_FAILURE() << "Unexpected failure: " << toString(std::move(Err));
144 }
145 
lookup(const DenseSet<StringRef> & Symbols,JITLinkAsyncLookupContinuation LookupContinuation)146 void JITLinkTestCommon::TestJITLinkContext::lookup(
147     const DenseSet<StringRef> &Symbols,
148     JITLinkAsyncLookupContinuation LookupContinuation) {
149   jitlink::AsyncLookupResult LookupResult;
150   DenseSet<StringRef> MissingSymbols;
151   for (const auto &Symbol : Symbols) {
152     auto I = Externals.find(Symbol);
153     if (I != Externals.end())
154       LookupResult[Symbol] = I->second;
155     else
156       MissingSymbols.insert(Symbol);
157   }
158 
159   if (MissingSymbols.empty())
160     LookupContinuation(std::move(LookupResult));
161   else {
162     std::string ErrMsg;
163     {
164       raw_string_ostream ErrMsgStream(ErrMsg);
165       ErrMsgStream << "Failed to resolve external symbols: [";
166       for (auto &Sym : MissingSymbols)
167         ErrMsgStream << " " << Sym;
168       ErrMsgStream << " ]\n";
169     }
170     LookupContinuation(
171         make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()));
172   }
173 }
174 
notifyResolved(AtomGraph & G)175 void JITLinkTestCommon::TestJITLinkContext::notifyResolved(AtomGraph &G) {
176   if (NotifyResolved)
177     NotifyResolved(G);
178 }
179 
notifyFinalized(std::unique_ptr<JITLinkMemoryManager::Allocation> A)180 void JITLinkTestCommon::TestJITLinkContext::notifyFinalized(
181     std::unique_ptr<JITLinkMemoryManager::Allocation> A) {
182   if (NotifyFinalized)
183     NotifyFinalized(std::move(A));
184 }
185 
modifyPassConfig(const Triple & TT,PassConfiguration & Config)186 Error JITLinkTestCommon::TestJITLinkContext::modifyPassConfig(
187     const Triple &TT, PassConfiguration &Config) {
188   if (TestCase)
189     Config.PostFixupPasses.push_back([&](AtomGraph &G) -> Error {
190       TestCase(G);
191       return Error::success();
192     });
193   return Error::success();
194 }
195 
JITLinkTestCommon()196 JITLinkTestCommon::JITLinkTestCommon() { initializeLLVMTargets(); }
197 
198 Expected<std::pair<MCInst, size_t>>
disassemble(const MCDisassembler & Dis,jitlink::DefinedAtom & Atom,size_t Offset)199 JITLinkTestCommon::disassemble(const MCDisassembler &Dis,
200                                jitlink::DefinedAtom &Atom, size_t Offset) {
201   ArrayRef<uint8_t> InstBuffer(
202       reinterpret_cast<const uint8_t *>(Atom.getContent().data()) + Offset,
203       Atom.getContent().size() - Offset);
204 
205   MCInst Inst;
206   uint64_t InstSize;
207   auto Status =
208       Dis.getInstruction(Inst, InstSize, InstBuffer, 0, nulls(), nulls());
209 
210   if (Status != MCDisassembler::Success)
211     return make_error<StringError>("Could not disassemble instruction",
212                                    inconvertibleErrorCode());
213 
214   return std::make_pair(Inst, InstSize);
215 }
216 
217 Expected<int64_t>
decodeImmediateOperand(const MCDisassembler & Dis,jitlink::DefinedAtom & Atom,size_t OpIdx,size_t Offset)218 JITLinkTestCommon::decodeImmediateOperand(const MCDisassembler &Dis,
219                                           jitlink::DefinedAtom &Atom,
220                                           size_t OpIdx, size_t Offset) {
221   auto InstAndSize = disassemble(Dis, Atom, Offset);
222   if (!InstAndSize)
223     return InstAndSize.takeError();
224 
225   if (OpIdx >= InstAndSize->first.getNumOperands())
226     return make_error<StringError>("Invalid operand index",
227                                    inconvertibleErrorCode());
228 
229   auto &Op = InstAndSize->first.getOperand(OpIdx);
230 
231   if (!Op.isImm())
232     return make_error<StringError>("Operand at index is not immediate",
233                                    inconvertibleErrorCode());
234 
235   return Op.getImm();
236 }
237 
238 bool JITLinkTestCommon::AreTargetsInitialized = false;
239 
initializeLLVMTargets()240 void JITLinkTestCommon::initializeLLVMTargets() {
241   if (!AreTargetsInitialized) {
242     InitializeAllTargets();
243     InitializeAllTargetMCs();
244     InitializeAllAsmParsers();
245     InitializeAllAsmPrinters();
246     InitializeAllDisassemblers();
247     AreTargetsInitialized = true;
248   }
249 }
250 
251 } // end namespace llvm
252