Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVAPI.cpp
213799 views
//===-- SPIRVAPI.cpp - SPIR-V Backend API ---------------------*- C++ -*---===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "SPIRVCommandLine.h"9#include "SPIRVSubtarget.h"10#include "SPIRVTargetMachine.h"11#include "llvm/Analysis/TargetLibraryInfo.h"12#include "llvm/CodeGen/CommandFlags.h"13#include "llvm/CodeGen/MachineModuleInfo.h"14#include "llvm/CodeGen/TargetPassConfig.h"15#include "llvm/CodeGen/TargetSubtargetInfo.h"16#include "llvm/IR/DataLayout.h"17#include "llvm/IR/LLVMContext.h"18#include "llvm/IR/LegacyPassManager.h"19#include "llvm/IR/Module.h"20#include "llvm/IR/Verifier.h"21#include "llvm/MC/TargetRegistry.h"22#include "llvm/Pass.h"23#include "llvm/Support/TargetSelect.h"24#include "llvm/Target/TargetLoweringObjectFile.h"25#include "llvm/Target/TargetMachine.h"26#include "llvm/TargetParser/SubtargetFeature.h"27#include "llvm/TargetParser/Triple.h"28#include <optional>29#include <string>30#include <vector>3132using namespace llvm;3334namespace {3536std::once_flag InitOnceFlag;37void InitializeSPIRVTarget() {38std::call_once(InitOnceFlag, []() {39LLVMInitializeSPIRVTargetInfo();40LLVMInitializeSPIRVTarget();41LLVMInitializeSPIRVTargetMC();42LLVMInitializeSPIRVAsmPrinter();43});44}45} // namespace4647namespace llvm {4849// The goal of this function is to facilitate integration of SPIRV Backend into50// tools and libraries by means of exposing an API call that translate LLVM51// module to SPIR-V and write results into a string as binary SPIR-V output,52// providing diagnostics on fail and means of configuring translation.53extern "C" LLVM_EXTERNAL_VISIBILITY bool54SPIRVTranslate(Module *M, std::string &SpirvObj, std::string &ErrMsg,55const std::vector<std::string> &AllowExtNames,56llvm::CodeGenOptLevel OLevel, Triple TargetTriple) {57// Fallbacks for option values.58static const std::string DefaultTriple = "spirv64-unknown-unknown";59static const std::string DefaultMArch = "";6061std::set<SPIRV::Extension::Extension> AllowedExtIds;62StringRef UnknownExt =63SPIRVExtensionsParser::checkExtensions(AllowExtNames, AllowedExtIds);64if (!UnknownExt.empty()) {65ErrMsg = "Unknown SPIR-V extension: " + UnknownExt.str();66return false;67}6869// SPIR-V-specific target initialization.70InitializeSPIRVTarget();7172if (TargetTriple.getTriple().empty()) {73TargetTriple.setTriple(DefaultTriple);74M->setTargetTriple(TargetTriple);75}76const Target *TheTarget =77TargetRegistry::lookupTarget(DefaultMArch, TargetTriple, ErrMsg);78if (!TheTarget)79return false;8081// A call to codegen::InitTargetOptionsFromCodeGenFlags(TargetTriple)82// hits the following assertion: llvm/lib/CodeGen/CommandFlags.cpp:78:83// llvm::FPOpFusion::FPOpFusionMode llvm::codegen::getFuseFPOps(): Assertion84// `FuseFPOpsView && "RegisterCodeGenFlags not created."' failed.85TargetOptions Options;86std::optional<Reloc::Model> RM;87std::optional<CodeModel::Model> CM;88std::unique_ptr<TargetMachine> Target(TheTarget->createTargetMachine(89TargetTriple, "", "", Options, RM, CM, OLevel));90if (!Target) {91ErrMsg = "Could not allocate target machine!";92return false;93}9495// Set available extensions.96SPIRVTargetMachine *STM = static_cast<SPIRVTargetMachine *>(Target.get());97const_cast<SPIRVSubtarget *>(STM->getSubtargetImpl())98->initAvailableExtensions(AllowedExtIds);99100if (M->getCodeModel())101Target->setCodeModel(*M->getCodeModel());102103std::string DLStr = M->getDataLayoutStr();104Expected<DataLayout> MaybeDL = DataLayout::parse(105DLStr.empty() ? Target->createDataLayout().getStringRepresentation()106: DLStr);107if (!MaybeDL) {108ErrMsg = toString(MaybeDL.takeError());109return false;110}111M->setDataLayout(MaybeDL.get());112113TargetLibraryInfoImpl TLII(M->getTargetTriple());114legacy::PassManager PM;115PM.add(new TargetLibraryInfoWrapperPass(TLII));116std::unique_ptr<MachineModuleInfoWrapperPass> MMIWP(117new MachineModuleInfoWrapperPass(Target.get()));118const_cast<TargetLoweringObjectFile *>(Target->getObjFileLowering())119->Initialize(MMIWP->getMMI().getContext(), *Target);120121SmallString<4096> OutBuffer;122raw_svector_ostream OutStream(OutBuffer);123if (Target->addPassesToEmitFile(PM, OutStream, nullptr,124CodeGenFileType::ObjectFile)) {125ErrMsg = "Target machine cannot emit a file of this type";126return false;127}128129PM.run(*M);130SpirvObj = OutBuffer.str();131132return true;133}134135// TODO: Remove this wrapper after existing clients switch into a newer136// implementation of SPIRVTranslate().137extern "C" LLVM_EXTERNAL_VISIBILITY bool138SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,139const std::vector<std::string> &AllowExtNames,140const std::vector<std::string> &Opts) {141// optional: Opts[0] is a string representation of Triple,142// take Module triple otherwise143Triple TargetTriple = Opts.empty() || Opts[0].empty()144? M->getTargetTriple()145: Triple(Triple::normalize(Opts[0]));146// optional: Opts[1] is a string representation of CodeGenOptLevel,147// no optimization otherwise148llvm::CodeGenOptLevel OLevel = CodeGenOptLevel::None;149if (Opts.size() > 1 && !Opts[1].empty()) {150if (auto Level = CodeGenOpt::parseLevel(Opts[1][0])) {151OLevel = *Level;152} else {153ErrMsg = "Invalid optimization level!";154return false;155}156}157return SPIRVTranslate(M, SpirvObj, ErrMsg, AllowExtNames, OLevel,158TargetTriple);159}160161} // namespace llvm162163164