1//===-- TargetMachine.cpp -------------------------------------------------===//
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// This file implements the LLVM-C part of TargetMachine.h
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm-c/Core.h"
14#include "llvm-c/TargetMachine.h"
15#include "llvm/Analysis/TargetTransformInfo.h"
16#include "llvm/IR/DataLayout.h"
17#include "llvm/IR/LegacyPassManager.h"
18#include "llvm/IR/Module.h"
19#include "llvm/MC/TargetRegistry.h"
20#include "llvm/Support/CBindingWrapping.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/raw_ostream.h"
23#include "llvm/Target/CodeGenCWrappers.h"
24#include "llvm/Target/TargetMachine.h"
25#include "llvm/TargetParser/Host.h"
26#include "llvm/TargetParser/SubtargetFeature.h"
27#include <cstring>
28#include <optional>
29
30using namespace llvm;
31
32namespace llvm {
33
34/// Options for LLVMCreateTargetMachine().
35struct LLVMTargetMachineOptions {
36 std::string CPU;
37 std::string Features;
38 std::string ABI;
39 CodeGenOptLevel OL = CodeGenOptLevel::Default;
40 std::optional<Reloc::Model> RM;
41 std::optional<CodeModel::Model> CM;
42 bool JIT;
43};
44
45} // namespace llvm
46
47DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMTargetMachineOptions,
48 LLVMTargetMachineOptionsRef)
49
50static TargetMachine *unwrap(LLVMTargetMachineRef P) {
51 return reinterpret_cast<TargetMachine *>(P);
52}
53static Target *unwrap(LLVMTargetRef P) {
54 return reinterpret_cast<Target*>(P);
55}
56static LLVMTargetMachineRef wrap(const TargetMachine *P) {
57 return reinterpret_cast<LLVMTargetMachineRef>(const_cast<TargetMachine *>(P));
58}
59static LLVMTargetRef wrap(const Target * P) {
60 return reinterpret_cast<LLVMTargetRef>(const_cast<Target*>(P));
61}
62
63LLVMTargetRef LLVMGetFirstTarget() {
64 if (TargetRegistry::targets().begin() == TargetRegistry::targets().end()) {
65 return nullptr;
66 }
67
68 const Target *target = &*TargetRegistry::targets().begin();
69 return wrap(P: target);
70}
71LLVMTargetRef LLVMGetNextTarget(LLVMTargetRef T) {
72 return wrap(P: unwrap(P: T)->getNext());
73}
74
75LLVMTargetRef LLVMGetTargetFromName(const char *Name) {
76 StringRef NameRef = Name;
77 auto I = find_if(Range: TargetRegistry::targets(),
78 P: [&](const Target &T) { return T.getName() == NameRef; });
79 return I != TargetRegistry::targets().end() ? wrap(P: &*I) : nullptr;
80}
81
82LLVMBool LLVMGetTargetFromTriple(const char* TripleStr, LLVMTargetRef *T,
83 char **ErrorMessage) {
84 std::string Error;
85
86 Triple TT(TripleStr);
87 *T = wrap(P: TargetRegistry::lookupTarget(TheTriple: TT, Error));
88
89 if (!*T) {
90 if (ErrorMessage)
91 *ErrorMessage = strdup(s: Error.c_str());
92
93 return 1;
94 }
95
96 return 0;
97}
98
99const char * LLVMGetTargetName(LLVMTargetRef T) {
100 return unwrap(P: T)->getName();
101}
102
103const char * LLVMGetTargetDescription(LLVMTargetRef T) {
104 return unwrap(P: T)->getShortDescription();
105}
106
107LLVMBool LLVMTargetHasJIT(LLVMTargetRef T) {
108 return unwrap(P: T)->hasJIT();
109}
110
111LLVMBool LLVMTargetHasTargetMachine(LLVMTargetRef T) {
112 return unwrap(P: T)->hasTargetMachine();
113}
114
115LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T) {
116 return unwrap(P: T)->hasMCAsmBackend();
117}
118
119LLVMTargetMachineOptionsRef LLVMCreateTargetMachineOptions(void) {
120 return wrap(P: new LLVMTargetMachineOptions());
121}
122
123void LLVMDisposeTargetMachineOptions(LLVMTargetMachineOptionsRef Options) {
124 delete unwrap(P: Options);
125}
126
127void LLVMTargetMachineOptionsSetCPU(LLVMTargetMachineOptionsRef Options,
128 const char *CPU) {
129 unwrap(P: Options)->CPU = CPU;
130}
131
132void LLVMTargetMachineOptionsSetFeatures(LLVMTargetMachineOptionsRef Options,
133 const char *Features) {
134 unwrap(P: Options)->Features = Features;
135}
136
137void LLVMTargetMachineOptionsSetABI(LLVMTargetMachineOptionsRef Options,
138 const char *ABI) {
139 unwrap(P: Options)->ABI = ABI;
140}
141
142void LLVMTargetMachineOptionsSetCodeGenOptLevel(
143 LLVMTargetMachineOptionsRef Options, LLVMCodeGenOptLevel Level) {
144 CodeGenOptLevel OL;
145
146 switch (Level) {
147 case LLVMCodeGenLevelNone:
148 OL = CodeGenOptLevel::None;
149 break;
150 case LLVMCodeGenLevelLess:
151 OL = CodeGenOptLevel::Less;
152 break;
153 case LLVMCodeGenLevelAggressive:
154 OL = CodeGenOptLevel::Aggressive;
155 break;
156 case LLVMCodeGenLevelDefault:
157 OL = CodeGenOptLevel::Default;
158 break;
159 }
160
161 unwrap(P: Options)->OL = OL;
162}
163
164void LLVMTargetMachineOptionsSetRelocMode(LLVMTargetMachineOptionsRef Options,
165 LLVMRelocMode Reloc) {
166 std::optional<Reloc::Model> RM;
167
168 switch (Reloc) {
169 case LLVMRelocStatic:
170 RM = Reloc::Static;
171 break;
172 case LLVMRelocPIC:
173 RM = Reloc::PIC_;
174 break;
175 case LLVMRelocDynamicNoPic:
176 RM = Reloc::DynamicNoPIC;
177 break;
178 case LLVMRelocROPI:
179 RM = Reloc::ROPI;
180 break;
181 case LLVMRelocRWPI:
182 RM = Reloc::RWPI;
183 break;
184 case LLVMRelocROPI_RWPI:
185 RM = Reloc::ROPI_RWPI;
186 break;
187 case LLVMRelocDefault:
188 break;
189 }
190
191 unwrap(P: Options)->RM = RM;
192}
193
194void LLVMTargetMachineOptionsSetCodeModel(LLVMTargetMachineOptionsRef Options,
195 LLVMCodeModel CodeModel) {
196 auto CM = unwrap(Model: CodeModel, JIT&: unwrap(P: Options)->JIT);
197 unwrap(P: Options)->CM = CM;
198}
199
200LLVMTargetMachineRef
201LLVMCreateTargetMachineWithOptions(LLVMTargetRef T, const char *TripleStr,
202 LLVMTargetMachineOptionsRef Options) {
203 auto *Opt = unwrap(P: Options);
204 TargetOptions TO;
205 TO.MCOptions.ABIName = Opt->ABI;
206 return wrap(P: unwrap(P: T)->createTargetMachine(TT: Triple(TripleStr), CPU: Opt->CPU,
207 Features: Opt->Features, Options: TO, RM: Opt->RM,
208 CM: Opt->CM, OL: Opt->OL, JIT: Opt->JIT));
209}
210
211LLVMTargetMachineRef
212LLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple, const char *CPU,
213 const char *Features, LLVMCodeGenOptLevel Level,
214 LLVMRelocMode Reloc, LLVMCodeModel CodeModel) {
215 auto *Options = LLVMCreateTargetMachineOptions();
216
217 LLVMTargetMachineOptionsSetCPU(Options, CPU);
218 LLVMTargetMachineOptionsSetFeatures(Options, Features);
219 LLVMTargetMachineOptionsSetCodeGenOptLevel(Options, Level);
220 LLVMTargetMachineOptionsSetRelocMode(Options, Reloc);
221 LLVMTargetMachineOptionsSetCodeModel(Options, CodeModel);
222
223 auto *Machine = LLVMCreateTargetMachineWithOptions(T, TripleStr: Triple, Options);
224
225 LLVMDisposeTargetMachineOptions(Options);
226 return Machine;
227}
228
229void LLVMDisposeTargetMachine(LLVMTargetMachineRef T) { delete unwrap(P: T); }
230
231LLVMTargetRef LLVMGetTargetMachineTarget(LLVMTargetMachineRef T) {
232 const Target* target = &(unwrap(P: T)->getTarget());
233 return wrap(P: target);
234}
235
236char* LLVMGetTargetMachineTriple(LLVMTargetMachineRef T) {
237 std::string StringRep = unwrap(P: T)->getTargetTriple().str();
238 return strdup(s: StringRep.c_str());
239}
240
241char* LLVMGetTargetMachineCPU(LLVMTargetMachineRef T) {
242 std::string StringRep = std::string(unwrap(P: T)->getTargetCPU());
243 return strdup(s: StringRep.c_str());
244}
245
246char* LLVMGetTargetMachineFeatureString(LLVMTargetMachineRef T) {
247 std::string StringRep = std::string(unwrap(P: T)->getTargetFeatureString());
248 return strdup(s: StringRep.c_str());
249}
250
251void LLVMSetTargetMachineAsmVerbosity(LLVMTargetMachineRef T,
252 LLVMBool VerboseAsm) {
253 unwrap(P: T)->Options.MCOptions.AsmVerbose = VerboseAsm;
254}
255
256void LLVMSetTargetMachineFastISel(LLVMTargetMachineRef T, LLVMBool Enable) {
257 unwrap(P: T)->setFastISel(Enable);
258}
259
260void LLVMSetTargetMachineGlobalISel(LLVMTargetMachineRef T, LLVMBool Enable) {
261 unwrap(P: T)->setGlobalISel(Enable);
262}
263
264void LLVMSetTargetMachineGlobalISelAbort(LLVMTargetMachineRef T,
265 LLVMGlobalISelAbortMode Mode) {
266 GlobalISelAbortMode AM = GlobalISelAbortMode::Enable;
267 switch (Mode) {
268 case LLVMGlobalISelAbortDisable:
269 AM = GlobalISelAbortMode::Disable;
270 break;
271 case LLVMGlobalISelAbortEnable:
272 AM = GlobalISelAbortMode::Enable;
273 break;
274 case LLVMGlobalISelAbortDisableWithDiag:
275 AM = GlobalISelAbortMode::DisableWithDiag;
276 break;
277 }
278
279 unwrap(P: T)->setGlobalISelAbort(AM);
280}
281
282void LLVMSetTargetMachineMachineOutliner(LLVMTargetMachineRef T,
283 LLVMBool Enable) {
284 unwrap(P: T)->setMachineOutliner(Enable);
285}
286
287LLVMTargetDataRef LLVMCreateTargetDataLayout(LLVMTargetMachineRef T) {
288 return wrap(P: new DataLayout(unwrap(P: T)->createDataLayout()));
289}
290
291static LLVMBool LLVMTargetMachineEmit(LLVMTargetMachineRef T, LLVMModuleRef M,
292 raw_pwrite_stream &OS,
293 LLVMCodeGenFileType codegen,
294 char **ErrorMessage) {
295 TargetMachine* TM = unwrap(P: T);
296 Module* Mod = unwrap(P: M);
297
298 legacy::PassManager pass;
299
300 std::string error;
301
302 Mod->setDataLayout(TM->createDataLayout());
303
304 CodeGenFileType ft;
305 switch (codegen) {
306 case LLVMAssemblyFile:
307 ft = CodeGenFileType::AssemblyFile;
308 break;
309 default:
310 ft = CodeGenFileType::ObjectFile;
311 break;
312 }
313 if (TM->addPassesToEmitFile(pass, OS, nullptr, ft)) {
314 error = "TargetMachine can't emit a file of this type";
315 *ErrorMessage = strdup(s: error.c_str());
316 return true;
317 }
318
319 pass.run(M&: *Mod);
320
321 OS.flush();
322 return false;
323}
324
325LLVMBool LLVMTargetMachineEmitToFile(LLVMTargetMachineRef T, LLVMModuleRef M,
326 const char *Filename,
327 LLVMCodeGenFileType codegen,
328 char **ErrorMessage) {
329 std::error_code EC;
330 raw_fd_ostream dest(Filename, EC, sys::fs::OF_None);
331 if (EC) {
332 *ErrorMessage = strdup(s: EC.message().c_str());
333 return true;
334 }
335 bool Result = LLVMTargetMachineEmit(T, M, OS&: dest, codegen, ErrorMessage);
336 dest.flush();
337 return Result;
338}
339
340LLVMBool LLVMTargetMachineEmitToMemoryBuffer(LLVMTargetMachineRef T,
341 LLVMModuleRef M, LLVMCodeGenFileType codegen, char** ErrorMessage,
342 LLVMMemoryBufferRef *OutMemBuf) {
343 SmallString<0> CodeString;
344 raw_svector_ostream OStream(CodeString);
345 bool Result = LLVMTargetMachineEmit(T, M, OS&: OStream, codegen, ErrorMessage);
346
347 StringRef Data = OStream.str();
348 *OutMemBuf =
349 LLVMCreateMemoryBufferWithMemoryRangeCopy(InputData: Data.data(), InputDataLength: Data.size(), BufferName: "");
350 return Result;
351}
352
353char *LLVMGetDefaultTargetTriple(void) {
354 return strdup(s: sys::getDefaultTargetTriple().c_str());
355}
356
357char *LLVMNormalizeTargetTriple(const char* triple) {
358 return strdup(s: Triple::normalize(Str: StringRef(triple)).c_str());
359}
360
361char *LLVMGetHostCPUName(void) {
362 return strdup(s: sys::getHostCPUName().data());
363}
364
365char *LLVMGetHostCPUFeatures(void) {
366 SubtargetFeatures Features;
367 for (const auto &[Feature, IsEnabled] : sys::getHostCPUFeatures())
368 Features.AddFeature(String: Feature, Enable: IsEnabled);
369
370 return strdup(s: Features.getString().c_str());
371}
372
373void LLVMAddAnalysisPasses(LLVMTargetMachineRef T, LLVMPassManagerRef PM) {
374 unwrap(P: PM)->add(
375 P: createTargetTransformInfoWrapperPass(TIRA: unwrap(P: T)->getTargetIRAnalysis()));
376}
377