[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.
This commit is contained in:
committed by
GitHub
parent
72d8e47a2c
commit
3351097c7b
@@ -167,6 +167,11 @@ Changes to the C API
|
||||
* ``LLVMConstAnd``
|
||||
* ``LLVMConstOr``
|
||||
|
||||
* Added ``LLVMCreateTargetMachineWithOptions``, along with helper functions for
|
||||
an opaque option structure, as an alternative to ``LLVMCreateTargetMachine``.
|
||||
The option structure exposes an additional setting (i.e., the target ABI) and
|
||||
provides default values for unspecified settings.
|
||||
|
||||
Changes to the CodeGen infrastructure
|
||||
-------------------------------------
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ LLVM_C_EXTERN_C_BEGIN
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct LLVMOpaqueTargetMachineOptions *LLVMTargetMachineOptionsRef;
|
||||
typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
|
||||
typedef struct LLVMTarget *LLVMTargetRef;
|
||||
|
||||
@@ -98,6 +99,55 @@ LLVMBool LLVMTargetHasTargetMachine(LLVMTargetRef T);
|
||||
LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T);
|
||||
|
||||
/*===-- Target Machine ----------------------------------------------------===*/
|
||||
/**
|
||||
* Create a new set of options for an llvm::TargetMachine.
|
||||
*
|
||||
* The returned option structure must be released with
|
||||
* LLVMDisposeTargetMachineOptions() after the call to
|
||||
* LLVMCreateTargetMachineWithOptions().
|
||||
*/
|
||||
LLVMTargetMachineOptionsRef LLVMCreateTargetMachineOptions(void);
|
||||
|
||||
/**
|
||||
* Dispose of an LLVMTargetMachineOptionsRef instance.
|
||||
*/
|
||||
void LLVMDisposeTargetMachineOptions(LLVMTargetMachineOptionsRef Options);
|
||||
|
||||
void LLVMTargetMachineOptionsSetCPU(LLVMTargetMachineOptionsRef Options,
|
||||
const char *CPU);
|
||||
|
||||
/**
|
||||
* Set the list of features for the target machine.
|
||||
*
|
||||
* \param Features a comma-separated list of features.
|
||||
*/
|
||||
void LLVMTargetMachineOptionsSetFeatures(LLVMTargetMachineOptionsRef Options,
|
||||
const char *Features);
|
||||
|
||||
void LLVMTargetMachineOptionsSetABI(LLVMTargetMachineOptionsRef Options,
|
||||
const char *ABI);
|
||||
|
||||
void LLVMTargetMachineOptionsSetCodeGenOptLevel(
|
||||
LLVMTargetMachineOptionsRef Options, LLVMCodeGenOptLevel Level);
|
||||
|
||||
void LLVMTargetMachineOptionsSetRelocMode(LLVMTargetMachineOptionsRef Options,
|
||||
LLVMRelocMode Reloc);
|
||||
|
||||
void LLVMTargetMachineOptionsSetCodeModel(LLVMTargetMachineOptionsRef Options,
|
||||
LLVMCodeModel CodeModel);
|
||||
|
||||
/**
|
||||
* Create a new llvm::TargetMachine.
|
||||
*
|
||||
* \param T the target to create a machine for.
|
||||
* \param Triple a triple describing the target machine.
|
||||
* \param Options additional configuration (see
|
||||
* LLVMCreateTargetMachineOptions()).
|
||||
*/
|
||||
LLVMTargetMachineRef
|
||||
LLVMCreateTargetMachineWithOptions(LLVMTargetRef T, const char *Triple,
|
||||
LLVMTargetMachineOptionsRef Options);
|
||||
|
||||
/** Creates a new llvm::TargetMachine. See llvm::Target::createTargetMachine */
|
||||
LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T,
|
||||
const char *Triple, const char *CPU, const char *Features,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/MC/TargetRegistry.h"
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/CodeGenCWrappers.h"
|
||||
@@ -28,6 +29,24 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Options for LLVMCreateTargetMachine().
|
||||
struct LLVMTargetMachineOptions {
|
||||
std::string CPU;
|
||||
std::string Features;
|
||||
std::string ABI;
|
||||
CodeGenOptLevel OL = CodeGenOptLevel::Default;
|
||||
std::optional<Reloc::Model> RM;
|
||||
std::optional<CodeModel::Model> CM;
|
||||
bool JIT;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMTargetMachineOptions,
|
||||
LLVMTargetMachineOptionsRef)
|
||||
|
||||
static TargetMachine *unwrap(LLVMTargetMachineRef P) {
|
||||
return reinterpret_cast<TargetMachine *>(P);
|
||||
}
|
||||
@@ -96,56 +115,114 @@ LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T) {
|
||||
return unwrap(T)->hasMCAsmBackend();
|
||||
}
|
||||
|
||||
LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T,
|
||||
const char *Triple, const char *CPU, const char *Features,
|
||||
LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc,
|
||||
LLVMCodeModel CodeModel) {
|
||||
std::optional<Reloc::Model> RM;
|
||||
switch (Reloc){
|
||||
case LLVMRelocStatic:
|
||||
RM = Reloc::Static;
|
||||
break;
|
||||
case LLVMRelocPIC:
|
||||
RM = Reloc::PIC_;
|
||||
break;
|
||||
case LLVMRelocDynamicNoPic:
|
||||
RM = Reloc::DynamicNoPIC;
|
||||
break;
|
||||
case LLVMRelocROPI:
|
||||
RM = Reloc::ROPI;
|
||||
break;
|
||||
case LLVMRelocRWPI:
|
||||
RM = Reloc::RWPI;
|
||||
break;
|
||||
case LLVMRelocROPI_RWPI:
|
||||
RM = Reloc::ROPI_RWPI;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LLVMTargetMachineOptionsRef LLVMCreateTargetMachineOptions(void) {
|
||||
return wrap(new LLVMTargetMachineOptions());
|
||||
}
|
||||
|
||||
bool JIT;
|
||||
std::optional<CodeModel::Model> CM = unwrap(CodeModel, JIT);
|
||||
void LLVMDisposeTargetMachineOptions(LLVMTargetMachineOptionsRef Options) {
|
||||
delete unwrap(Options);
|
||||
}
|
||||
|
||||
void LLVMTargetMachineOptionsSetCPU(LLVMTargetMachineOptionsRef Options,
|
||||
const char *CPU) {
|
||||
unwrap(Options)->CPU = CPU;
|
||||
}
|
||||
|
||||
void LLVMTargetMachineOptionsSetFeatures(LLVMTargetMachineOptionsRef Options,
|
||||
const char *Features) {
|
||||
unwrap(Options)->Features = Features;
|
||||
}
|
||||
|
||||
void LLVMTargetMachineOptionsSetABI(LLVMTargetMachineOptionsRef Options,
|
||||
const char *ABI) {
|
||||
unwrap(Options)->ABI = ABI;
|
||||
}
|
||||
|
||||
void LLVMTargetMachineOptionsSetCodeGenOptLevel(
|
||||
LLVMTargetMachineOptionsRef Options, LLVMCodeGenOptLevel Level) {
|
||||
CodeGenOptLevel OL;
|
||||
|
||||
switch (Level) {
|
||||
case LLVMCodeGenLevelNone:
|
||||
OL = CodeGenOptLevel::None;
|
||||
break;
|
||||
case LLVMCodeGenLevelLess:
|
||||
OL = CodeGenOptLevel::Less;
|
||||
break;
|
||||
case LLVMCodeGenLevelAggressive:
|
||||
OL = CodeGenOptLevel::Aggressive;
|
||||
break;
|
||||
default:
|
||||
OL = CodeGenOptLevel::Default;
|
||||
break;
|
||||
case LLVMCodeGenLevelNone:
|
||||
OL = CodeGenOptLevel::None;
|
||||
break;
|
||||
case LLVMCodeGenLevelLess:
|
||||
OL = CodeGenOptLevel::Less;
|
||||
break;
|
||||
case LLVMCodeGenLevelAggressive:
|
||||
OL = CodeGenOptLevel::Aggressive;
|
||||
break;
|
||||
case LLVMCodeGenLevelDefault:
|
||||
OL = CodeGenOptLevel::Default;
|
||||
break;
|
||||
}
|
||||
|
||||
TargetOptions opt;
|
||||
return wrap(unwrap(T)->createTargetMachine(Triple, CPU, Features, opt, RM, CM,
|
||||
OL, JIT));
|
||||
unwrap(Options)->OL = OL;
|
||||
}
|
||||
|
||||
void LLVMTargetMachineOptionsSetRelocMode(LLVMTargetMachineOptionsRef Options,
|
||||
LLVMRelocMode Reloc) {
|
||||
std::optional<Reloc::Model> RM;
|
||||
|
||||
switch (Reloc) {
|
||||
case LLVMRelocStatic:
|
||||
RM = Reloc::Static;
|
||||
break;
|
||||
case LLVMRelocPIC:
|
||||
RM = Reloc::PIC_;
|
||||
break;
|
||||
case LLVMRelocDynamicNoPic:
|
||||
RM = Reloc::DynamicNoPIC;
|
||||
break;
|
||||
case LLVMRelocROPI:
|
||||
RM = Reloc::ROPI;
|
||||
break;
|
||||
case LLVMRelocRWPI:
|
||||
RM = Reloc::RWPI;
|
||||
break;
|
||||
case LLVMRelocROPI_RWPI:
|
||||
RM = Reloc::ROPI_RWPI;
|
||||
break;
|
||||
case LLVMRelocDefault:
|
||||
break;
|
||||
}
|
||||
|
||||
unwrap(Options)->RM = RM;
|
||||
}
|
||||
|
||||
void LLVMTargetMachineOptionsSetCodeModel(LLVMTargetMachineOptionsRef Options,
|
||||
LLVMCodeModel CodeModel) {
|
||||
auto CM = unwrap(CodeModel, unwrap(Options)->JIT);
|
||||
unwrap(Options)->CM = CM;
|
||||
}
|
||||
|
||||
LLVMTargetMachineRef
|
||||
LLVMCreateTargetMachineWithOptions(LLVMTargetRef T, const char *Triple,
|
||||
LLVMTargetMachineOptionsRef Options) {
|
||||
auto *Opt = unwrap(Options);
|
||||
TargetOptions TO;
|
||||
TO.MCOptions.ABIName = Opt->ABI;
|
||||
return wrap(unwrap(T)->createTargetMachine(Triple, Opt->CPU, Opt->Features,
|
||||
TO, Opt->RM, Opt->CM, Opt->OL,
|
||||
Opt->JIT));
|
||||
}
|
||||
|
||||
LLVMTargetMachineRef
|
||||
LLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple, const char *CPU,
|
||||
const char *Features, LLVMCodeGenOptLevel Level,
|
||||
LLVMRelocMode Reloc, LLVMCodeModel CodeModel) {
|
||||
auto *Options = LLVMCreateTargetMachineOptions();
|
||||
|
||||
LLVMTargetMachineOptionsSetCPU(Options, CPU);
|
||||
LLVMTargetMachineOptionsSetFeatures(Options, Features);
|
||||
LLVMTargetMachineOptionsSetCodeGenOptLevel(Options, Level);
|
||||
LLVMTargetMachineOptionsSetRelocMode(Options, Reloc);
|
||||
LLVMTargetMachineOptionsSetCodeModel(Options, CodeModel);
|
||||
|
||||
auto *Machine = LLVMCreateTargetMachineWithOptions(T, Triple, Options);
|
||||
|
||||
LLVMDisposeTargetMachineOptions(Options);
|
||||
return Machine;
|
||||
}
|
||||
|
||||
void LLVMDisposeTargetMachine(LLVMTargetMachineRef T) { delete unwrap(T); }
|
||||
|
||||
@@ -3,3 +3,12 @@ foreach(t ${LLVM_TARGETS_TO_BUILD})
|
||||
add_subdirectory(${t})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(LLVM_LINK_COMPONENTS Target AllTargetsCodeGens)
|
||||
|
||||
add_llvm_unittest(TargetMachineCTests
|
||||
TargetMachineOptionsTest.cpp
|
||||
)
|
||||
|
||||
set_property(TARGET TargetMachineCTests
|
||||
PROPERTY FOLDER "Tests/UnitTests/TargetTests")
|
||||
|
||||
73
llvm/unittests/Target/TargetMachineOptionsTest.cpp
Normal file
73
llvm/unittests/Target/TargetMachineOptionsTest.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
//===-- llvm/unittests/Target/TargetMachineOptionsTest.cpp ----------
|
||||
//-----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file contains unit tests for the opaque structure describing options
|
||||
/// for TargetMachine creation via the C API.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/TargetMachine.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
TEST(TargetMachineCTest, TargetMachineOptions) {
|
||||
auto *Options = LLVMCreateTargetMachineOptions();
|
||||
|
||||
LLVMTargetMachineOptionsSetCPU(Options, "cortex-a53");
|
||||
LLVMTargetMachineOptionsSetFeatures(Options, "+neon");
|
||||
LLVMTargetMachineOptionsSetABI(Options, "aapcs");
|
||||
LLVMTargetMachineOptionsSetCodeGenOptLevel(Options, LLVMCodeGenLevelNone);
|
||||
LLVMTargetMachineOptionsSetRelocMode(Options, LLVMRelocStatic);
|
||||
LLVMTargetMachineOptionsSetCodeModel(Options, LLVMCodeModelKernel);
|
||||
|
||||
LLVMDisposeTargetMachineOptions(Options);
|
||||
}
|
||||
|
||||
TEST(TargetMachineCTest, TargetMachineCreation) {
|
||||
LLVMInitializeAllTargets();
|
||||
LLVMInitializeAllTargetInfos();
|
||||
LLVMInitializeAllTargetMCs();
|
||||
|
||||
// Get the default target to keep the test as generic as possible. This may
|
||||
// not be a target for which we can generate code; in that case we give up.
|
||||
|
||||
auto *Triple = LLVMGetDefaultTargetTriple();
|
||||
if (strlen(Triple) == 0) {
|
||||
LLVMDisposeMessage(Triple);
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
LLVMTargetRef Target = nullptr;
|
||||
char *Error = nullptr;
|
||||
if (LLVMGetTargetFromTriple(Triple, &Target, &Error))
|
||||
FAIL() << "Failed to create target from default triple (" << Triple
|
||||
<< "): " << Error;
|
||||
|
||||
ASSERT_NE(Target, nullptr);
|
||||
|
||||
if (!LLVMTargetHasTargetMachine(Target))
|
||||
GTEST_SKIP() << "Default target doesn't support code generation";
|
||||
|
||||
// We don't know which target we're creating a machine for, so don't set any
|
||||
// non-default options; they might cause fatal errors.
|
||||
|
||||
auto *Options = LLVMCreateTargetMachineOptions();
|
||||
auto *TM = LLVMCreateTargetMachineWithOptions(Target, Triple, Options);
|
||||
ASSERT_NE(TM, nullptr);
|
||||
|
||||
LLVMDisposeMessage(Triple);
|
||||
LLVMDisposeTargetMachineOptions(Options);
|
||||
LLVMDisposeTargetMachine(TM);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
Reference in New Issue
Block a user