Skip to content

Commit 3351097

Browse files
[LLVM-C] Add LLVMCreateTargetMachineWithABI (#68406)
The ABI parameter is used by a number of common backends, including ARM, MIPS, PPC, and RISCV. Exposing it via the C API makes it possible for users of those backends to configure the ABI without custom bindings.
1 parent 72d8e47 commit 3351097

File tree

5 files changed

+258
-44
lines changed

5 files changed

+258
-44
lines changed

llvm/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ Changes to the C API
167167
* ``LLVMConstAnd``
168168
* ``LLVMConstOr``
169169

170+
* Added ``LLVMCreateTargetMachineWithOptions``, along with helper functions for
171+
an opaque option structure, as an alternative to ``LLVMCreateTargetMachine``.
172+
The option structure exposes an additional setting (i.e., the target ABI) and
173+
provides default values for unspecified settings.
174+
170175
Changes to the CodeGen infrastructure
171176
-------------------------------------
172177

llvm/include/llvm-c/TargetMachine.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ LLVM_C_EXTERN_C_BEGIN
3131
* @{
3232
*/
3333

34+
typedef struct LLVMOpaqueTargetMachineOptions *LLVMTargetMachineOptionsRef;
3435
typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
3536
typedef struct LLVMTarget *LLVMTargetRef;
3637

@@ -98,6 +99,55 @@ LLVMBool LLVMTargetHasTargetMachine(LLVMTargetRef T);
9899
LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T);
99100

100101
/*===-- Target Machine ----------------------------------------------------===*/
102+
/**
103+
* Create a new set of options for an llvm::TargetMachine.
104+
*
105+
* The returned option structure must be released with
106+
* LLVMDisposeTargetMachineOptions() after the call to
107+
* LLVMCreateTargetMachineWithOptions().
108+
*/
109+
LLVMTargetMachineOptionsRef LLVMCreateTargetMachineOptions(void);
110+
111+
/**
112+
* Dispose of an LLVMTargetMachineOptionsRef instance.
113+
*/
114+
void LLVMDisposeTargetMachineOptions(LLVMTargetMachineOptionsRef Options);
115+
116+
void LLVMTargetMachineOptionsSetCPU(LLVMTargetMachineOptionsRef Options,
117+
const char *CPU);
118+
119+
/**
120+
* Set the list of features for the target machine.
121+
*
122+
* \param Features a comma-separated list of features.
123+
*/
124+
void LLVMTargetMachineOptionsSetFeatures(LLVMTargetMachineOptionsRef Options,
125+
const char *Features);
126+
127+
void LLVMTargetMachineOptionsSetABI(LLVMTargetMachineOptionsRef Options,
128+
const char *ABI);
129+
130+
void LLVMTargetMachineOptionsSetCodeGenOptLevel(
131+
LLVMTargetMachineOptionsRef Options, LLVMCodeGenOptLevel Level);
132+
133+
void LLVMTargetMachineOptionsSetRelocMode(LLVMTargetMachineOptionsRef Options,
134+
LLVMRelocMode Reloc);
135+
136+
void LLVMTargetMachineOptionsSetCodeModel(LLVMTargetMachineOptionsRef Options,
137+
LLVMCodeModel CodeModel);
138+
139+
/**
140+
* Create a new llvm::TargetMachine.
141+
*
142+
* \param T the target to create a machine for.
143+
* \param Triple a triple describing the target machine.
144+
* \param Options additional configuration (see
145+
* LLVMCreateTargetMachineOptions()).
146+
*/
147+
LLVMTargetMachineRef
148+
LLVMCreateTargetMachineWithOptions(LLVMTargetRef T, const char *Triple,
149+
LLVMTargetMachineOptionsRef Options);
150+
101151
/** Creates a new llvm::TargetMachine. See llvm::Target::createTargetMachine */
102152
LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T,
103153
const char *Triple, const char *CPU, const char *Features,

llvm/lib/Target/TargetMachineC.cpp

Lines changed: 121 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "llvm/IR/LegacyPassManager.h"
1818
#include "llvm/IR/Module.h"
1919
#include "llvm/MC/TargetRegistry.h"
20+
#include "llvm/Support/CBindingWrapping.h"
2021
#include "llvm/Support/FileSystem.h"
2122
#include "llvm/Support/raw_ostream.h"
2223
#include "llvm/Target/CodeGenCWrappers.h"
@@ -28,6 +29,24 @@
2829

2930
using namespace llvm;
3031

32+
namespace llvm {
33+
34+
/// Options for LLVMCreateTargetMachine().
35+
struct 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+
47+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMTargetMachineOptions,
48+
LLVMTargetMachineOptionsRef)
49+
3150
static TargetMachine *unwrap(LLVMTargetMachineRef P) {
3251
return reinterpret_cast<TargetMachine *>(P);
3352
}
@@ -96,56 +115,114 @@ LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T) {
96115
return unwrap(T)->hasMCAsmBackend();
97116
}
98117

99-
LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T,
100-
const char *Triple, const char *CPU, const char *Features,
101-
LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc,
102-
LLVMCodeModel CodeModel) {
103-
std::optional<Reloc::Model> RM;
104-
switch (Reloc){
105-
case LLVMRelocStatic:
106-
RM = Reloc::Static;
107-
break;
108-
case LLVMRelocPIC:
109-
RM = Reloc::PIC_;
110-
break;
111-
case LLVMRelocDynamicNoPic:
112-
RM = Reloc::DynamicNoPIC;
113-
break;
114-
case LLVMRelocROPI:
115-
RM = Reloc::ROPI;
116-
break;
117-
case LLVMRelocRWPI:
118-
RM = Reloc::RWPI;
119-
break;
120-
case LLVMRelocROPI_RWPI:
121-
RM = Reloc::ROPI_RWPI;
122-
break;
123-
default:
124-
break;
125-
}
118+
LLVMTargetMachineOptionsRef LLVMCreateTargetMachineOptions(void) {
119+
return wrap(new LLVMTargetMachineOptions());
120+
}
126121

127-
bool JIT;
128-
std::optional<CodeModel::Model> CM = unwrap(CodeModel, JIT);
122+
void LLVMDisposeTargetMachineOptions(LLVMTargetMachineOptionsRef Options) {
123+
delete unwrap(Options);
124+
}
125+
126+
void LLVMTargetMachineOptionsSetCPU(LLVMTargetMachineOptionsRef Options,
127+
const char *CPU) {
128+
unwrap(Options)->CPU = CPU;
129+
}
130+
131+
void LLVMTargetMachineOptionsSetFeatures(LLVMTargetMachineOptionsRef Options,
132+
const char *Features) {
133+
unwrap(Options)->Features = Features;
134+
}
129135

136+
void LLVMTargetMachineOptionsSetABI(LLVMTargetMachineOptionsRef Options,
137+
const char *ABI) {
138+
unwrap(Options)->ABI = ABI;
139+
}
140+
141+
void LLVMTargetMachineOptionsSetCodeGenOptLevel(
142+
LLVMTargetMachineOptionsRef Options, LLVMCodeGenOptLevel Level) {
130143
CodeGenOptLevel OL;
144+
131145
switch (Level) {
132-
case LLVMCodeGenLevelNone:
133-
OL = CodeGenOptLevel::None;
134-
break;
135-
case LLVMCodeGenLevelLess:
136-
OL = CodeGenOptLevel::Less;
137-
break;
138-
case LLVMCodeGenLevelAggressive:
139-
OL = CodeGenOptLevel::Aggressive;
140-
break;
141-
default:
142-
OL = CodeGenOptLevel::Default;
143-
break;
146+
case LLVMCodeGenLevelNone:
147+
OL = CodeGenOptLevel::None;
148+
break;
149+
case LLVMCodeGenLevelLess:
150+
OL = CodeGenOptLevel::Less;
151+
break;
152+
case LLVMCodeGenLevelAggressive:
153+
OL = CodeGenOptLevel::Aggressive;
154+
break;
155+
case LLVMCodeGenLevelDefault:
156+
OL = CodeGenOptLevel::Default;
157+
break;
144158
}
145159

146-
TargetOptions opt;
147-
return wrap(unwrap(T)->createTargetMachine(Triple, CPU, Features, opt, RM, CM,
148-
OL, JIT));
160+
unwrap(Options)->OL = OL;
161+
}
162+
163+
void LLVMTargetMachineOptionsSetRelocMode(LLVMTargetMachineOptionsRef Options,
164+
LLVMRelocMode Reloc) {
165+
std::optional<Reloc::Model> RM;
166+
167+
switch (Reloc) {
168+
case LLVMRelocStatic:
169+
RM = Reloc::Static;
170+
break;
171+
case LLVMRelocPIC:
172+
RM = Reloc::PIC_;
173+
break;
174+
case LLVMRelocDynamicNoPic:
175+
RM = Reloc::DynamicNoPIC;
176+
break;
177+
case LLVMRelocROPI:
178+
RM = Reloc::ROPI;
179+
break;
180+
case LLVMRelocRWPI:
181+
RM = Reloc::RWPI;
182+
break;
183+
case LLVMRelocROPI_RWPI:
184+
RM = Reloc::ROPI_RWPI;
185+
break;
186+
case LLVMRelocDefault:
187+
break;
188+
}
189+
190+
unwrap(Options)->RM = RM;
191+
}
192+
193+
void LLVMTargetMachineOptionsSetCodeModel(LLVMTargetMachineOptionsRef Options,
194+
LLVMCodeModel CodeModel) {
195+
auto CM = unwrap(CodeModel, unwrap(Options)->JIT);
196+
unwrap(Options)->CM = CM;
197+
}
198+
199+
LLVMTargetMachineRef
200+
LLVMCreateTargetMachineWithOptions(LLVMTargetRef T, const char *Triple,
201+
LLVMTargetMachineOptionsRef Options) {
202+
auto *Opt = unwrap(Options);
203+
TargetOptions TO;
204+
TO.MCOptions.ABIName = Opt->ABI;
205+
return wrap(unwrap(T)->createTargetMachine(Triple, Opt->CPU, Opt->Features,
206+
TO, Opt->RM, Opt->CM, Opt->OL,
207+
Opt->JIT));
208+
}
209+
210+
LLVMTargetMachineRef
211+
LLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple, const char *CPU,
212+
const char *Features, LLVMCodeGenOptLevel Level,
213+
LLVMRelocMode Reloc, LLVMCodeModel CodeModel) {
214+
auto *Options = LLVMCreateTargetMachineOptions();
215+
216+
LLVMTargetMachineOptionsSetCPU(Options, CPU);
217+
LLVMTargetMachineOptionsSetFeatures(Options, Features);
218+
LLVMTargetMachineOptionsSetCodeGenOptLevel(Options, Level);
219+
LLVMTargetMachineOptionsSetRelocMode(Options, Reloc);
220+
LLVMTargetMachineOptionsSetCodeModel(Options, CodeModel);
221+
222+
auto *Machine = LLVMCreateTargetMachineWithOptions(T, Triple, Options);
223+
224+
LLVMDisposeTargetMachineOptions(Options);
225+
return Machine;
149226
}
150227

151228
void LLVMDisposeTargetMachine(LLVMTargetMachineRef T) { delete unwrap(T); }

llvm/unittests/Target/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,12 @@ foreach(t ${LLVM_TARGETS_TO_BUILD})
33
add_subdirectory(${t})
44
endif()
55
endforeach()
6+
7+
set(LLVM_LINK_COMPONENTS Target AllTargetsCodeGens)
8+
9+
add_llvm_unittest(TargetMachineCTests
10+
TargetMachineOptionsTest.cpp
11+
)
12+
13+
set_property(TARGET TargetMachineCTests
14+
PROPERTY FOLDER "Tests/UnitTests/TargetTests")
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//===-- llvm/unittests/Target/TargetMachineOptionsTest.cpp ----------
2+
//-----===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// \file
11+
/// This file contains unit tests for the opaque structure describing options
12+
/// for TargetMachine creation via the C API.
13+
///
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "llvm-c/Core.h"
17+
#include "llvm-c/TargetMachine.h"
18+
#include "llvm/Config/llvm-config.h"
19+
#include "gtest/gtest.h"
20+
21+
namespace llvm {
22+
23+
TEST(TargetMachineCTest, TargetMachineOptions) {
24+
auto *Options = LLVMCreateTargetMachineOptions();
25+
26+
LLVMTargetMachineOptionsSetCPU(Options, "cortex-a53");
27+
LLVMTargetMachineOptionsSetFeatures(Options, "+neon");
28+
LLVMTargetMachineOptionsSetABI(Options, "aapcs");
29+
LLVMTargetMachineOptionsSetCodeGenOptLevel(Options, LLVMCodeGenLevelNone);
30+
LLVMTargetMachineOptionsSetRelocMode(Options, LLVMRelocStatic);
31+
LLVMTargetMachineOptionsSetCodeModel(Options, LLVMCodeModelKernel);
32+
33+
LLVMDisposeTargetMachineOptions(Options);
34+
}
35+
36+
TEST(TargetMachineCTest, TargetMachineCreation) {
37+
LLVMInitializeAllTargets();
38+
LLVMInitializeAllTargetInfos();
39+
LLVMInitializeAllTargetMCs();
40+
41+
// Get the default target to keep the test as generic as possible. This may
42+
// not be a target for which we can generate code; in that case we give up.
43+
44+
auto *Triple = LLVMGetDefaultTargetTriple();
45+
if (strlen(Triple) == 0) {
46+
LLVMDisposeMessage(Triple);
47+
GTEST_SKIP();
48+
}
49+
50+
LLVMTargetRef Target = nullptr;
51+
char *Error = nullptr;
52+
if (LLVMGetTargetFromTriple(Triple, &Target, &Error))
53+
FAIL() << "Failed to create target from default triple (" << Triple
54+
<< "): " << Error;
55+
56+
ASSERT_NE(Target, nullptr);
57+
58+
if (!LLVMTargetHasTargetMachine(Target))
59+
GTEST_SKIP() << "Default target doesn't support code generation";
60+
61+
// We don't know which target we're creating a machine for, so don't set any
62+
// non-default options; they might cause fatal errors.
63+
64+
auto *Options = LLVMCreateTargetMachineOptions();
65+
auto *TM = LLVMCreateTargetMachineWithOptions(Target, Triple, Options);
66+
ASSERT_NE(TM, nullptr);
67+
68+
LLVMDisposeMessage(Triple);
69+
LLVMDisposeTargetMachineOptions(Options);
70+
LLVMDisposeTargetMachine(TM);
71+
}
72+
73+
} // namespace llvm

0 commit comments

Comments
 (0)