[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:
Sebastian Poeplau
2023-10-31 16:55:00 +01:00
committed by GitHub
parent 72d8e47a2c
commit 3351097c7b
5 changed files with 258 additions and 44 deletions

View File

@@ -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
-------------------------------------

View File

@@ -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,

View File

@@ -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); }

View File

@@ -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")

View 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