1
Fork 0

Move rustllvm into rustc_llvm

This commit is contained in:
Vadim Petrochenkov 2020-07-26 20:11:30 +03:00
parent d92155bf6a
commit 10d3f8a484
17 changed files with 23 additions and 27 deletions

View file

@ -0,0 +1,16 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_llvm"
version = "0.0.0"
edition = "2018"
[features]
static-libstdcpp = []
emscripten = []
[dependencies]
libc = "0.2.73"
[build-dependencies]
build_helper = { path = "../../src/build_helper" }
cc = "1.0.58"

View file

@ -0,0 +1,322 @@
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use build_helper::{output, tracked_env_var_os};
fn detect_llvm_link() -> (&'static str, &'static str) {
// Force the link mode we want, preferring static by default, but
// possibly overridden by `configure --enable-llvm-link-shared`.
if tracked_env_var_os("LLVM_LINK_SHARED").is_some() {
("dylib", "--link-shared")
} else {
("static", "--link-static")
}
}
fn main() {
if tracked_env_var_os("RUST_CHECK").is_some() {
// If we're just running `check`, there's no need for LLVM to be built.
return;
}
build_helper::restore_library_path();
let target = env::var("TARGET").expect("TARGET was not set");
let llvm_config =
tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
let to_test = dir
.parent()
.unwrap()
.parent()
.unwrap()
.join(&target)
.join("llvm/bin/llvm-config");
if Command::new(&to_test).output().is_ok() {
return Some(to_test);
}
}
None
});
if let Some(llvm_config) = &llvm_config {
println!("cargo:rerun-if-changed={}", llvm_config.display());
}
let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config"));
// Test whether we're cross-compiling LLVM. This is a pretty rare case
// currently where we're producing an LLVM for a different platform than
// what this build script is currently running on.
//
// In that case, there's no guarantee that we can actually run the target,
// so the build system works around this by giving us the LLVM_CONFIG for
// the host platform. This only really works if the host LLVM and target
// LLVM are compiled the same way, but for us that's typically the case.
//
// We *want* detect this cross compiling situation by asking llvm-config
// what its host-target is. If that's not the TARGET, then we're cross
// compiling. Unfortunately `llvm-config` seems either be buggy, or we're
// misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
// report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
// tricks us into thinking we're doing a cross build when we aren't, so
// havoc ensues.
//
// In any case, if we're cross compiling, this generally just means that we
// can't trust all the output of llvm-config because it might be targeted
// for the host rather than the target. As a result a bunch of blocks below
// are gated on `if !is_crossed`
let target = env::var("TARGET").expect("TARGET was not set");
let host = env::var("HOST").expect("HOST was not set");
let is_crossed = target != host;
let mut optional_components = vec![
"x86",
"arm",
"aarch64",
"amdgpu",
"avr",
"mips",
"powerpc",
"systemz",
"jsbackend",
"webassembly",
"msp430",
"sparc",
"nvptx",
"hexagon",
];
let mut version_cmd = Command::new(&llvm_config);
version_cmd.arg("--version");
let version_output = output(&mut version_cmd);
let mut parts = version_output.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
let (major, _minor) = if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
(major, minor)
} else {
(6, 0)
};
if major > 6 {
optional_components.push("riscv");
}
let required_components = &[
"ipo",
"bitreader",
"bitwriter",
"linker",
"asmparser",
"lto",
"coverage",
"instrumentation",
];
let components = output(Command::new(&llvm_config).arg("--components"));
let mut components = components.split_whitespace().collect::<Vec<_>>();
components.retain(|c| optional_components.contains(c) || required_components.contains(c));
for component in required_components {
if !components.contains(component) {
panic!("require llvm component {} but wasn't found", component);
}
}
for component in components.iter() {
println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
}
if major >= 9 {
println!("cargo:rustc-cfg=llvm_has_msp430_asm_parser");
}
// Link in our own LLVM shims, compiled with the same flags as LLVM
let mut cmd = Command::new(&llvm_config);
cmd.arg("--cxxflags");
let cxxflags = output(&mut cmd);
let mut cfg = cc::Build::new();
cfg.warnings(false);
for flag in cxxflags.split_whitespace() {
// Ignore flags like `-m64` when we're doing a cross build
if is_crossed && flag.starts_with("-m") {
continue;
}
if flag.starts_with("-flto") {
continue;
}
// -Wdate-time is not supported by the netbsd cross compiler
if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
continue;
}
// Include path contains host directory, replace it with target
if is_crossed && flag.starts_with("-I") {
cfg.flag(&flag.replace(&host, &target));
continue;
}
cfg.flag(flag);
}
for component in &components {
let mut flag = String::from("LLVM_COMPONENT_");
flag.push_str(&component.to_uppercase());
cfg.define(&flag, None);
}
if tracked_env_var_os("LLVM_RUSTLLVM").is_some() {
cfg.define("LLVM_RUSTLLVM", None);
}
if tracked_env_var_os("LLVM_NDEBUG").is_some() {
cfg.define("NDEBUG", None);
cfg.debug(false);
}
build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
cfg.file("llvm-wrapper/PassWrapper.cpp")
.file("llvm-wrapper/RustWrapper.cpp")
.file("llvm-wrapper/ArchiveWrapper.cpp")
.file("llvm-wrapper/CoverageMappingWrapper.cpp")
.file("llvm-wrapper/Linker.cpp")
.cpp(true)
.cpp_link_stdlib(None) // we handle this below
.compile("llvm-wrapper");
let (llvm_kind, llvm_link_arg) = detect_llvm_link();
// Link in all LLVM libraries, if we're using the "wrong" llvm-config then
// we don't pick up system libs because unfortunately they're for the host
// of llvm-config, not the target that we're attempting to link.
let mut cmd = Command::new(&llvm_config);
cmd.arg(llvm_link_arg).arg("--libs");
if !is_crossed {
cmd.arg("--system-libs");
} else if target.contains("windows-gnu") {
println!("cargo:rustc-link-lib=shell32");
println!("cargo:rustc-link-lib=uuid");
} else if target.contains("netbsd") || target.contains("haiku") {
println!("cargo:rustc-link-lib=z");
}
cmd.args(&components);
for lib in output(&mut cmd).split_whitespace() {
let name = if lib.starts_with("-l") {
&lib[2..]
} else if lib.starts_with('-') {
&lib[1..]
} else if Path::new(lib).exists() {
// On MSVC llvm-config will print the full name to libraries, but
// we're only interested in the name part
let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
name.trim_end_matches(".lib")
} else if lib.ends_with(".lib") {
// Some MSVC libraries just come up with `.lib` tacked on, so chop
// that off
lib.trim_end_matches(".lib")
} else {
continue;
};
// Don't need or want this library, but LLVM's CMake build system
// doesn't provide a way to disable it, so filter it here even though we
// may or may not have built it. We don't reference anything from this
// library and it otherwise may just pull in extra dependencies on
// libedit which we don't want
if name == "LLVMLineEditor" {
continue;
}
let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" };
println!("cargo:rustc-link-lib={}={}", kind, name);
}
// LLVM ldflags
//
// If we're a cross-compile of LLVM then unfortunately we can't trust these
// ldflags (largely where all the LLVM libs are located). Currently just
// hack around this by replacing the host triple with the target and pray
// that those -L directories are the same!
let mut cmd = Command::new(&llvm_config);
cmd.arg(llvm_link_arg).arg("--ldflags");
for lib in output(&mut cmd).split_whitespace() {
if is_crossed {
if lib.starts_with("-LIBPATH:") {
println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target));
} else if lib.starts_with("-L") {
println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target));
}
} else if lib.starts_with("-LIBPATH:") {
println!("cargo:rustc-link-search=native={}", &lib[9..]);
} else if lib.starts_with("-l") {
println!("cargo:rustc-link-lib={}", &lib[2..]);
} else if lib.starts_with("-L") {
println!("cargo:rustc-link-search=native={}", &lib[2..]);
}
}
// Some LLVM linker flags (-L and -l) may be needed even when linking
// rustc_llvm, for example when using static libc++, we may need to
// manually specify the library search path and -ldl -lpthread as link
// dependencies.
let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
if let Some(s) = llvm_linker_flags {
for lib in s.into_string().unwrap().split_whitespace() {
if lib.starts_with("-l") {
println!("cargo:rustc-link-lib={}", &lib[2..]);
} else if lib.starts_with("-L") {
println!("cargo:rustc-link-search=native={}", &lib[2..]);
}
}
}
let llvm_static_stdcpp = tracked_env_var_os("LLVM_STATIC_STDCPP");
let llvm_use_libcxx = tracked_env_var_os("LLVM_USE_LIBCXX");
let stdcppname = if target.contains("openbsd") {
if target.contains("sparc64") { "estdc++" } else { "c++" }
} else if target.contains("freebsd") {
"c++"
} else if target.contains("darwin") {
"c++"
} else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
// NetBSD uses a separate library when relocation is required
"stdc++_pic"
} else if llvm_use_libcxx.is_some() {
"c++"
} else {
"stdc++"
};
// RISC-V requires libatomic for sub-word atomic operations
if target.starts_with("riscv") {
println!("cargo:rustc-link-lib=atomic");
}
// C++ runtime library
if !target.contains("msvc") {
if let Some(s) = llvm_static_stdcpp {
assert!(!cxxflags.contains("stdlib=libc++"));
let path = PathBuf::from(s);
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
if target.contains("windows") {
println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname);
} else {
println!("cargo:rustc-link-lib=static={}", stdcppname);
}
} else if cxxflags.contains("stdlib=libc++") {
println!("cargo:rustc-link-lib=c++");
} else {
println!("cargo:rustc-link-lib={}", stdcppname);
}
}
// Libstdc++ depends on pthread which Rust doesn't link on MinGW
// since nothing else requires it.
if target.contains("windows-gnu") {
println!("cargo:rustc-link-lib=static-nobundle=pthread");
}
}

View file

@ -0,0 +1,6 @@
[*.{h,cpp}]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2

View file

@ -0,0 +1,226 @@
#include "LLVMWrapper.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Support/Path.h"
using namespace llvm;
using namespace llvm::object;
struct RustArchiveMember {
const char *Filename;
const char *Name;
Archive::Child Child;
RustArchiveMember()
: Filename(nullptr), Name(nullptr),
Child(nullptr, nullptr, nullptr)
{
}
~RustArchiveMember() {}
};
struct RustArchiveIterator {
bool First;
Archive::child_iterator Cur;
Archive::child_iterator End;
std::unique_ptr<Error> Err;
RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End,
std::unique_ptr<Error> Err)
: First(true),
Cur(Cur),
End(End),
Err(std::move(Err)) {}
};
enum class LLVMRustArchiveKind {
GNU,
BSD,
DARWIN,
COFF,
};
static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
switch (Kind) {
case LLVMRustArchiveKind::GNU:
return Archive::K_GNU;
case LLVMRustArchiveKind::BSD:
return Archive::K_BSD;
case LLVMRustArchiveKind::DARWIN:
return Archive::K_DARWIN;
case LLVMRustArchiveKind::COFF:
return Archive::K_COFF;
default:
report_fatal_error("Bad ArchiveKind.");
}
}
typedef OwningBinary<Archive> *LLVMRustArchiveRef;
typedef RustArchiveMember *LLVMRustArchiveMemberRef;
typedef Archive::Child *LLVMRustArchiveChildRef;
typedef Archive::Child const *LLVMRustArchiveChildConstRef;
typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
MemoryBuffer::getFile(Path, -1, false);
if (!BufOr) {
LLVMRustSetLastError(BufOr.getError().message().c_str());
return nullptr;
}
Expected<std::unique_ptr<Archive>> ArchiveOr =
Archive::create(BufOr.get()->getMemBufferRef());
if (!ArchiveOr) {
LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
return nullptr;
}
OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
std::move(ArchiveOr.get()), std::move(BufOr.get()));
return Ret;
}
extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
delete RustArchive;
}
extern "C" LLVMRustArchiveIteratorRef
LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
Archive *Archive = RustArchive->getBinary();
#if LLVM_VERSION_GE(10, 0)
std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
#else
std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success());
#endif
auto Cur = Archive->child_begin(*Err);
if (*Err) {
LLVMRustSetLastError(toString(std::move(*Err)).c_str());
return nullptr;
}
auto End = Archive->child_end();
return new RustArchiveIterator(Cur, End, std::move(Err));
}
extern "C" LLVMRustArchiveChildConstRef
LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
if (RAI->Cur == RAI->End)
return nullptr;
// Advancing the iterator validates the next child, and this can
// uncover an error. LLVM requires that we check all Errors,
// so we only advance the iterator if we actually need to fetch
// the next child.
// This means we must not advance the iterator in the *first* call,
// but instead advance it *before* fetching the child in all later calls.
if (!RAI->First) {
++RAI->Cur;
if (*RAI->Err) {
LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
return nullptr;
}
} else {
RAI->First = false;
}
if (RAI->Cur == RAI->End)
return nullptr;
const Archive::Child &Child = *RAI->Cur.operator->();
Archive::Child *Ret = new Archive::Child(Child);
return Ret;
}
extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
delete Child;
}
extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
delete RAI;
}
extern "C" const char *
LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
Expected<StringRef> NameOrErr = Child->getName();
if (!NameOrErr) {
// rustc_codegen_llvm currently doesn't use this error string, but it might be
// useful in the future, and in the mean time this tells LLVM that the
// error was not ignored and that it shouldn't abort the process.
LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
return nullptr;
}
StringRef Name = NameOrErr.get();
*Size = Name.size();
return Name.data();
}
extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
size_t *Size) {
StringRef Buf;
Expected<StringRef> BufOrErr = Child->getBuffer();
if (!BufOrErr) {
LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
return nullptr;
}
Buf = BufOrErr.get();
*Size = Buf.size();
return Buf.data();
}
extern "C" LLVMRustArchiveMemberRef
LLVMRustArchiveMemberNew(char *Filename, char *Name,
LLVMRustArchiveChildRef Child) {
RustArchiveMember *Member = new RustArchiveMember;
Member->Filename = Filename;
Member->Name = Name;
if (Child)
Member->Child = *Child;
return Member;
}
extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
delete Member;
}
extern "C" LLVMRustResult
LLVMRustWriteArchive(char *Dst, size_t NumMembers,
const LLVMRustArchiveMemberRef *NewMembers,
bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
std::vector<NewArchiveMember> Members;
auto Kind = fromRust(RustKind);
for (size_t I = 0; I < NumMembers; I++) {
auto Member = NewMembers[I];
assert(Member->Name);
if (Member->Filename) {
Expected<NewArchiveMember> MOrErr =
NewArchiveMember::getFile(Member->Filename, true);
if (!MOrErr) {
LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
return LLVMRustResult::Failure;
}
MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
Members.push_back(std::move(*MOrErr));
} else {
Expected<NewArchiveMember> MOrErr =
NewArchiveMember::getOldMember(Member->Child, true);
if (!MOrErr) {
LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
return LLVMRustResult::Failure;
}
Members.push_back(std::move(*MOrErr));
}
}
auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
if (!Result)
return LLVMRustResult::Success;
LLVMRustSetLastError(toString(std::move(Result)).c_str());
return LLVMRustResult::Failure;
}

View file

@ -0,0 +1,70 @@
#include "LLVMWrapper.h"
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/LEB128.h"
#include <iostream>
using namespace llvm;
extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
const char* const Filenames[],
size_t FilenamesLen,
RustStringRef BufferOut) {
// LLVM 11's CoverageFilenamesSectionWriter uses its new `Version4` format,
// so we're manually writing the `Version3` format ourselves.
RawRustStringOstream OS(BufferOut);
encodeULEB128(FilenamesLen, OS);
for (size_t i = 0; i < FilenamesLen; i++) {
StringRef Filename(Filenames[i]);
encodeULEB128(Filename.size(), OS);
OS << Filename;
}
}
extern "C" void LLVMRustCoverageWriteMappingToBuffer(
const unsigned *VirtualFileMappingIDs,
unsigned NumVirtualFileMappingIDs,
const coverage::CounterExpression *Expressions,
unsigned NumExpressions,
coverage::CounterMappingRegion *MappingRegions,
unsigned NumMappingRegions,
RustStringRef BufferOut) {
auto CoverageMappingWriter = coverage::CoverageMappingWriter(
makeArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
makeArrayRef(Expressions, NumExpressions),
makeMutableArrayRef(MappingRegions, NumMappingRegions));
RawRustStringOstream OS(BufferOut);
CoverageMappingWriter.write(OS);
}
extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName) {
StringRef FuncNameRef(FuncName);
return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
}
extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) {
StringRef NameRef(Name);
return IndexedInstrProf::ComputeHash(NameRef);
}
extern "C" void LLVMRustCoverageWriteSectionNameToString(LLVMModuleRef M,
RustStringRef Str) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
auto name = getInstrProfSectionName(IPSK_covmap,
TargetTriple.getObjectFormat());
RawRustStringOstream OS(Str);
OS << name;
}
extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
auto name = getCoverageMappingVarName();
RawRustStringOstream OS(Str);
OS << name;
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
return coverage::CovMapVersion::Version3;
}

View file

@ -0,0 +1,115 @@
#include "llvm-c/BitReader.h"
#include "llvm-c/Core.h"
#include "llvm-c/Object.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/Lint.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Vectorize.h"
#define LLVM_VERSION_GE(major, minor) \
(LLVM_VERSION_MAJOR > (major) || \
LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR >= (minor))
#define LLVM_VERSION_EQ(major, minor) \
(LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR == (minor))
#define LLVM_VERSION_LE(major, minor) \
(LLVM_VERSION_MAJOR < (major) || \
LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR <= (minor))
#define LLVM_VERSION_LT(major, minor) (!LLVM_VERSION_GE((major), (minor)))
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/Linker/Linker.h"
extern "C" void LLVMRustSetLastError(const char *);
enum class LLVMRustResult { Success, Failure };
enum LLVMRustAttribute {
AlwaysInline = 0,
ByVal = 1,
Cold = 2,
InlineHint = 3,
MinSize = 4,
Naked = 5,
NoAlias = 6,
NoCapture = 7,
NoInline = 8,
NonNull = 9,
NoRedZone = 10,
NoReturn = 11,
NoUnwind = 12,
OptimizeForSize = 13,
ReadOnly = 14,
SExt = 15,
StructRet = 16,
UWTable = 17,
ZExt = 18,
InReg = 19,
SanitizeThread = 20,
SanitizeAddress = 21,
SanitizeMemory = 22,
NonLazyBind = 23,
OptimizeNone = 24,
ReturnsTwice = 25,
ReadNone = 26,
InaccessibleMemOnly = 27,
};
typedef struct OpaqueRustString *RustStringRef;
typedef struct LLVMOpaqueTwine *LLVMTwineRef;
typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef;
extern "C" void LLVMRustStringWriteImpl(RustStringRef Str, const char *Ptr,
size_t Size);
class RawRustStringOstream : public llvm::raw_ostream {
RustStringRef Str;
uint64_t Pos;
void write_impl(const char *Ptr, size_t Size) override {
LLVMRustStringWriteImpl(Str, Ptr, Size);
Pos += Size;
}
uint64_t current_pos() const override { return Pos; }
public:
explicit RawRustStringOstream(RustStringRef Str) : Str(Str), Pos(0) {}
~RawRustStringOstream() {
// LLVM requires this.
flush();
}
};

View file

@ -0,0 +1,48 @@
#include "llvm/Linker/Linker.h"
#include "LLVMWrapper.h"
using namespace llvm;
struct RustLinker {
Linker L;
LLVMContext &Ctx;
RustLinker(Module &M) :
L(M),
Ctx(M.getContext())
{}
};
extern "C" RustLinker*
LLVMRustLinkerNew(LLVMModuleRef DstRef) {
Module *Dst = unwrap(DstRef);
return new RustLinker(*Dst);
}
extern "C" void
LLVMRustLinkerFree(RustLinker *L) {
delete L;
}
extern "C" bool
LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) {
std::unique_ptr<MemoryBuffer> Buf =
MemoryBuffer::getMemBufferCopy(StringRef(BC, Len));
Expected<std::unique_ptr<Module>> SrcOrError =
llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx);
if (!SrcOrError) {
LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
return false;
}
auto Src = std::move(*SrcOrError);
if (L->L.linkInModule(std::move(Src))) {
LLVMRustSetLastError("");
return false;
}
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
This directory currently contains some LLVM support code. This will generally
be sent upstream to LLVM in time; for now it lives here.
NOTE: the LLVM C++ ABI is subject to between-version breakage and must *never*
be exposed to Rust. To allow for easy auditing of that, all Rust-exposed types
must be typedef-ed as "LLVMXyz", or "LLVMRustXyz" if they were defined here.
Functions that return a failure status and leave the error in
the LLVM last error should return an LLVMRustResult rather than an
int or anything to avoid confusion.
When translating enums, add a single `Other` variant as the first
one to allow for new variants to be added. It should abort when used
as an input.
All other types must not be typedef-ed as such.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,173 @@
#![feature(nll)]
#![feature(static_nobundle)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
// NOTE: This crate only exists to allow linking on mingw targets.
use libc::{c_char, size_t};
use std::cell::RefCell;
use std::slice;
#[repr(C)]
pub struct RustString {
pub bytes: RefCell<Vec<u8>>,
}
impl RustString {
pub fn len(&self) -> usize {
self.bytes.borrow().len()
}
}
/// Appending to a Rust string -- used by RawRustStringOstream.
#[no_mangle]
#[allow(improper_ctypes_definitions)]
pub unsafe extern "C" fn LLVMRustStringWriteImpl(
sr: &RustString,
ptr: *const c_char,
size: size_t,
) {
let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
sr.bytes.borrow_mut().extend_from_slice(slice);
}
/// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.
/// N.B., this function can't be moved to `rustc_codegen_llvm` because of the `cfg`s.
pub fn initialize_available_targets() {
macro_rules! init_target(
($cfg:meta, $($method:ident),*) => { {
#[cfg($cfg)]
fn init() {
extern {
$(fn $method();)*
}
unsafe {
$($method();)*
}
}
#[cfg(not($cfg))]
fn init() { }
init();
} }
);
init_target!(
llvm_component = "x86",
LLVMInitializeX86TargetInfo,
LLVMInitializeX86Target,
LLVMInitializeX86TargetMC,
LLVMInitializeX86AsmPrinter,
LLVMInitializeX86AsmParser
);
init_target!(
llvm_component = "arm",
LLVMInitializeARMTargetInfo,
LLVMInitializeARMTarget,
LLVMInitializeARMTargetMC,
LLVMInitializeARMAsmPrinter,
LLVMInitializeARMAsmParser
);
init_target!(
llvm_component = "aarch64",
LLVMInitializeAArch64TargetInfo,
LLVMInitializeAArch64Target,
LLVMInitializeAArch64TargetMC,
LLVMInitializeAArch64AsmPrinter,
LLVMInitializeAArch64AsmParser
);
init_target!(
llvm_component = "amdgpu",
LLVMInitializeAMDGPUTargetInfo,
LLVMInitializeAMDGPUTarget,
LLVMInitializeAMDGPUTargetMC,
LLVMInitializeAMDGPUAsmPrinter,
LLVMInitializeAMDGPUAsmParser
);
init_target!(
llvm_component = "avr",
LLVMInitializeAVRTargetInfo,
LLVMInitializeAVRTarget,
LLVMInitializeAVRTargetMC,
LLVMInitializeAVRAsmPrinter,
LLVMInitializeAVRAsmParser
);
init_target!(
llvm_component = "mips",
LLVMInitializeMipsTargetInfo,
LLVMInitializeMipsTarget,
LLVMInitializeMipsTargetMC,
LLVMInitializeMipsAsmPrinter,
LLVMInitializeMipsAsmParser
);
init_target!(
llvm_component = "powerpc",
LLVMInitializePowerPCTargetInfo,
LLVMInitializePowerPCTarget,
LLVMInitializePowerPCTargetMC,
LLVMInitializePowerPCAsmPrinter,
LLVMInitializePowerPCAsmParser
);
init_target!(
llvm_component = "systemz",
LLVMInitializeSystemZTargetInfo,
LLVMInitializeSystemZTarget,
LLVMInitializeSystemZTargetMC,
LLVMInitializeSystemZAsmPrinter,
LLVMInitializeSystemZAsmParser
);
init_target!(
llvm_component = "jsbackend",
LLVMInitializeJSBackendTargetInfo,
LLVMInitializeJSBackendTarget,
LLVMInitializeJSBackendTargetMC
);
init_target!(
llvm_component = "msp430",
LLVMInitializeMSP430TargetInfo,
LLVMInitializeMSP430Target,
LLVMInitializeMSP430TargetMC,
LLVMInitializeMSP430AsmPrinter
);
init_target!(
all(llvm_component = "msp430", llvm_has_msp430_asm_parser),
LLVMInitializeMSP430AsmParser
);
init_target!(
llvm_component = "riscv",
LLVMInitializeRISCVTargetInfo,
LLVMInitializeRISCVTarget,
LLVMInitializeRISCVTargetMC,
LLVMInitializeRISCVAsmPrinter,
LLVMInitializeRISCVAsmParser
);
init_target!(
llvm_component = "sparc",
LLVMInitializeSparcTargetInfo,
LLVMInitializeSparcTarget,
LLVMInitializeSparcTargetMC,
LLVMInitializeSparcAsmPrinter,
LLVMInitializeSparcAsmParser
);
init_target!(
llvm_component = "nvptx",
LLVMInitializeNVPTXTargetInfo,
LLVMInitializeNVPTXTarget,
LLVMInitializeNVPTXTargetMC,
LLVMInitializeNVPTXAsmPrinter
);
init_target!(
llvm_component = "hexagon",
LLVMInitializeHexagonTargetInfo,
LLVMInitializeHexagonTarget,
LLVMInitializeHexagonTargetMC,
LLVMInitializeHexagonAsmPrinter,
LLVMInitializeHexagonAsmParser
);
init_target!(
llvm_component = "webassembly",
LLVMInitializeWebAssemblyTargetInfo,
LLVMInitializeWebAssemblyTarget,
LLVMInitializeWebAssemblyTargetMC,
LLVMInitializeWebAssemblyAsmPrinter
);
}