| //===-- TargetMachine.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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the LLVM-C part of TargetMachine.h | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm-c/Core.h" | |
| #include "llvm-c/TargetMachine.h" | |
| #include "llvm/Analysis/TargetTransformInfo.h" | |
| #include "llvm/IR/DataLayout.h" | |
| #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" | |
| #include "llvm/Target/TargetMachine.h" | |
| #include "llvm/TargetParser/Host.h" | |
| #include "llvm/TargetParser/SubtargetFeature.h" | |
| #include <optional> | |
| 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); | |
| } | |
| static Target *unwrap(LLVMTargetRef P) { | |
| return reinterpret_cast<Target*>(P); | |
| } | |
| static LLVMTargetMachineRef wrap(const TargetMachine *P) { | |
| return reinterpret_cast<LLVMTargetMachineRef>(const_cast<TargetMachine *>(P)); | |
| } | |
| static LLVMTargetRef wrap(const Target * P) { | |
| return reinterpret_cast<LLVMTargetRef>(const_cast<Target*>(P)); | |
| } | |
| LLVMTargetRef LLVMGetFirstTarget() { | |
| if (TargetRegistry::targets().begin() == TargetRegistry::targets().end()) { | |
| return nullptr; | |
| } | |
| const Target *target = &*TargetRegistry::targets().begin(); | |
| return wrap(target); | |
| } | |
| LLVMTargetRef LLVMGetNextTarget(LLVMTargetRef T) { | |
| return wrap(unwrap(T)->getNext()); | |
| } | |
| LLVMTargetRef LLVMGetTargetFromName(const char *Name) { | |
| StringRef NameRef = Name; | |
| auto I = find_if(TargetRegistry::targets(), | |
| [&](const Target &T) { return T.getName() == NameRef; }); | |
| return I != TargetRegistry::targets().end() ? wrap(&*I) : nullptr; | |
| } | |
| LLVMBool LLVMGetTargetFromTriple(const char* TripleStr, LLVMTargetRef *T, | |
| char **ErrorMessage) { | |
| std::string Error; | |
| Triple TT(TripleStr); | |
| *T = wrap(TargetRegistry::lookupTarget(TT, Error)); | |
| if (!*T) { | |
| if (ErrorMessage) | |
| *ErrorMessage = strdup(Error.c_str()); | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| const char * LLVMGetTargetName(LLVMTargetRef T) { | |
| return unwrap(T)->getName(); | |
| } | |
| const char * LLVMGetTargetDescription(LLVMTargetRef T) { | |
| return unwrap(T)->getShortDescription(); | |
| } | |
| LLVMBool LLVMTargetHasJIT(LLVMTargetRef T) { | |
| return unwrap(T)->hasJIT(); | |
| } | |
| LLVMBool LLVMTargetHasTargetMachine(LLVMTargetRef T) { | |
| return unwrap(T)->hasTargetMachine(); | |
| } | |
| LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T) { | |
| return unwrap(T)->hasMCAsmBackend(); | |
| } | |
| LLVMTargetMachineOptionsRef LLVMCreateTargetMachineOptions(void) { | |
| return wrap(new LLVMTargetMachineOptions()); | |
| } | |
| 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; | |
| case LLVMCodeGenLevelDefault: | |
| OL = CodeGenOptLevel::Default; | |
| break; | |
| } | |
| 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 *TripleStr, | |
| LLVMTargetMachineOptionsRef Options) { | |
| auto *Opt = unwrap(Options); | |
| TargetOptions TO; | |
| TO.MCOptions.ABIName = Opt->ABI; | |
| return wrap(unwrap(T)->createTargetMachine(Triple(TripleStr), 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); } | |
| LLVMTargetRef LLVMGetTargetMachineTarget(LLVMTargetMachineRef T) { | |
| const Target* target = &(unwrap(T)->getTarget()); | |
| return wrap(target); | |
| } | |
| char* LLVMGetTargetMachineTriple(LLVMTargetMachineRef T) { | |
| std::string StringRep = unwrap(T)->getTargetTriple().str(); | |
| return strdup(StringRep.c_str()); | |
| } | |
| char* LLVMGetTargetMachineCPU(LLVMTargetMachineRef T) { | |
| std::string StringRep = std::string(unwrap(T)->getTargetCPU()); | |
| return strdup(StringRep.c_str()); | |
| } | |
| char* LLVMGetTargetMachineFeatureString(LLVMTargetMachineRef T) { | |
| std::string StringRep = std::string(unwrap(T)->getTargetFeatureString()); | |
| return strdup(StringRep.c_str()); | |
| } | |
| void LLVMSetTargetMachineAsmVerbosity(LLVMTargetMachineRef T, | |
| LLVMBool VerboseAsm) { | |
| unwrap(T)->Options.MCOptions.AsmVerbose = VerboseAsm; | |
| } | |
| void LLVMSetTargetMachineFastISel(LLVMTargetMachineRef T, LLVMBool Enable) { | |
| unwrap(T)->setFastISel(Enable); | |
| } | |
| void LLVMSetTargetMachineGlobalISel(LLVMTargetMachineRef T, LLVMBool Enable) { | |
| unwrap(T)->setGlobalISel(Enable); | |
| } | |
| void LLVMSetTargetMachineGlobalISelAbort(LLVMTargetMachineRef T, | |
| LLVMGlobalISelAbortMode Mode) { | |
| GlobalISelAbortMode AM = GlobalISelAbortMode::Enable; | |
| switch (Mode) { | |
| case LLVMGlobalISelAbortDisable: | |
| AM = GlobalISelAbortMode::Disable; | |
| break; | |
| case LLVMGlobalISelAbortEnable: | |
| AM = GlobalISelAbortMode::Enable; | |
| break; | |
| case LLVMGlobalISelAbortDisableWithDiag: | |
| AM = GlobalISelAbortMode::DisableWithDiag; | |
| break; | |
| } | |
| unwrap(T)->setGlobalISelAbort(AM); | |
| } | |
| void LLVMSetTargetMachineMachineOutliner(LLVMTargetMachineRef T, | |
| LLVMBool Enable) { | |
| unwrap(T)->setMachineOutliner(Enable); | |
| } | |
| LLVMTargetDataRef LLVMCreateTargetDataLayout(LLVMTargetMachineRef T) { | |
| TargetMachine *TM = unwrap(T); | |
| return wrap(new DataLayout(TM->getTargetTriple().computeDataLayout( | |
| TM->Options.MCOptions.getABIName()))); | |
| } | |
| static LLVMBool LLVMTargetMachineEmit(LLVMTargetMachineRef T, LLVMModuleRef M, | |
| raw_pwrite_stream &OS, | |
| LLVMCodeGenFileType codegen, | |
| char **ErrorMessage) { | |
| TargetMachine* TM = unwrap(T); | |
| Module* Mod = unwrap(M); | |
| legacy::PassManager pass; | |
| std::string error; | |
| Mod->setDataLayout(TM->getTargetTriple().computeDataLayout( | |
| TM->Options.MCOptions.getABIName())); | |
| CodeGenFileType ft; | |
| switch (codegen) { | |
| case LLVMAssemblyFile: | |
| ft = CodeGenFileType::AssemblyFile; | |
| break; | |
| default: | |
| ft = CodeGenFileType::ObjectFile; | |
| break; | |
| } | |
| if (TM->addPassesToEmitFile(pass, OS, nullptr, ft)) { | |
| error = "TargetMachine can't emit a file of this type"; | |
| *ErrorMessage = strdup(error.c_str()); | |
| return true; | |
| } | |
| pass.run(*Mod); | |
| OS.flush(); | |
| return false; | |
| } | |
| LLVMBool LLVMTargetMachineEmitToFile(LLVMTargetMachineRef T, LLVMModuleRef M, | |
| const char *Filename, | |
| LLVMCodeGenFileType codegen, | |
| char **ErrorMessage) { | |
| std::error_code EC; | |
| raw_fd_ostream dest(Filename, EC, sys::fs::OF_None); | |
| if (EC) { | |
| *ErrorMessage = strdup(EC.message().c_str()); | |
| return true; | |
| } | |
| bool Result = LLVMTargetMachineEmit(T, M, dest, codegen, ErrorMessage); | |
| dest.flush(); | |
| return Result; | |
| } | |
| LLVMBool LLVMTargetMachineEmitToMemoryBuffer(LLVMTargetMachineRef T, | |
| LLVMModuleRef M, LLVMCodeGenFileType codegen, char** ErrorMessage, | |
| LLVMMemoryBufferRef *OutMemBuf) { | |
| SmallString<0> CodeString; | |
| raw_svector_ostream OStream(CodeString); | |
| bool Result = LLVMTargetMachineEmit(T, M, OStream, codegen, ErrorMessage); | |
| StringRef Data = OStream.str(); | |
| *OutMemBuf = | |
| LLVMCreateMemoryBufferWithMemoryRangeCopy(Data.data(), Data.size(), ""); | |
| return Result; | |
| } | |
| char *LLVMGetDefaultTargetTriple(void) { | |
| return strdup(sys::getDefaultTargetTriple().c_str()); | |
| } | |
| char *LLVMNormalizeTargetTriple(const char* triple) { | |
| return strdup(Triple::normalize(StringRef(triple)).c_str()); | |
| } | |
| char *LLVMGetHostCPUName(void) { | |
| return strdup(sys::getHostCPUName().data()); | |
| } | |
| char *LLVMGetHostCPUFeatures(void) { | |
| SubtargetFeatures Features; | |
| for (const auto &[Feature, IsEnabled] : sys::getHostCPUFeatures()) | |
| Features.AddFeature(Feature, IsEnabled); | |
| return strdup(Features.getString().c_str()); | |
| } | |
| void LLVMAddAnalysisPasses(LLVMTargetMachineRef T, LLVMPassManagerRef PM) { | |
| unwrap(PM)->add( | |
| createTargetTransformInfoWrapperPass(unwrap(T)->getTargetIRAnalysis())); | |
| } |