From 696691e3c4f2b3aa02fbd1cc76dc2f7e8a401db8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 2 Aug 2016 00:16:16 +0300 Subject: [PATCH] audit LLVM C++ types in ArchiveWrapper and PassWrapper --- src/librustc_llvm/lib.rs | 76 ++++++++++------ src/librustc_trans/back/archive.rs | 2 +- src/librustc_trans/back/write.rs | 46 +++++----- src/librustc_trans/context.rs | 10 +-- src/rustllvm/ArchiveWrapper.cpp | 98 +++++++++++++------- src/rustllvm/PassWrapper.cpp | 138 +++++++++++++++++++++++------ src/rustllvm/README | 14 +++ src/rustllvm/rustllvm.h | 5 ++ 8 files changed, 275 insertions(+), 114 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index de82778bc5e..4019732221f 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -40,13 +40,9 @@ pub use self::TypeKind::*; pub use self::AtomicBinOp::*; pub use self::AtomicOrdering::*; pub use self::SynchronizationScope::*; -pub use self::FileType::*; pub use self::MetadataType::*; pub use self::AsmDialect::*; -pub use self::CodeGenOptLevel::*; pub use self::CodeGenOptSize::*; -pub use self::RelocMode::*; -pub use self::CodeGenModel::*; pub use self::DiagnosticKind::*; pub use self::CallConv::*; pub use self::Visibility::*; @@ -75,9 +71,26 @@ pub type Bool = c_uint; pub const True: Bool = 1 as Bool; pub const False: Bool = 0 as Bool; +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +pub enum LLVMRustResult { + Success = 0, + Failure = 1 +} + +impl LLVMRustResult { + pub fn into_result(self) -> Result<(), ()> { + match self { + LLVMRustResult::Success => Ok(()), + LLVMRustResult::Failure => Err(()), + } + } +} + // Consts for the LLVM CallConv type, pre-cast to usize. #[derive(Copy, Clone, PartialEq)] +#[repr(C)] pub enum CallConv { CCallConv = 0, FastCallConv = 8, @@ -89,6 +102,7 @@ pub enum CallConv { } #[derive(Copy, Clone)] +#[repr(C)] pub enum Visibility { LLVMDefaultVisibility = 0, HiddenVisibility = 1, @@ -100,6 +114,7 @@ pub enum Visibility { // LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; // they've been removed in upstream LLVM commit r203866. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[repr(C)] pub enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, @@ -337,12 +352,12 @@ pub enum SynchronizationScope { CrossThread = 1 } -// Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h) #[repr(C)] #[derive(Copy, Clone)] pub enum FileType { - AssemblyFileType = 0, - ObjectFileType = 1 + Other, + AssemblyFile, + ObjectFile, } #[derive(Copy, Clone)] @@ -371,10 +386,11 @@ pub enum AsmDialect { #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum CodeGenOptLevel { - CodeGenLevelNone = 0, - CodeGenLevelLess = 1, - CodeGenLevelDefault = 2, - CodeGenLevelAggressive = 3, + Other, + None, + Less, + Default, + Aggressive, } #[derive(Copy, Clone, PartialEq)] @@ -388,21 +404,22 @@ pub enum CodeGenOptSize { #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum RelocMode { - RelocDefault = 0, - RelocStatic = 1, - RelocPIC = 2, - RelocDynamicNoPic = 3, + Default = 0, + Static = 1, + PIC = 2, + DynamicNoPic = 3, } #[repr(C)] #[derive(Copy, Clone)] -pub enum CodeGenModel { - CodeModelDefault = 0, - CodeModelJITDefault = 1, - CodeModelSmall = 2, - CodeModelKernel = 3, - CodeModelMedium = 4, - CodeModelLarge = 5, +pub enum CodeModel { + Other, + Default, + JITDefault, + Small, + Kernel, + Medium, + Large, } #[repr(C)] @@ -421,6 +438,7 @@ pub enum DiagnosticKind { #[repr(C)] #[derive(Copy, Clone)] pub enum ArchiveKind { + Other, K_GNU, K_MIPS64, K_BSD, @@ -444,10 +462,10 @@ impl FromStr for ArchiveKind { /// Represents the different LLVM passes Rust supports #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] -pub enum SupportedPassKind { +pub enum PassKind { + Other, Function, Module, - Unsupported, } // Opaque pointer types @@ -2021,7 +2039,7 @@ extern { pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; - pub fn LLVMRustPassKind(Pass: PassRef) -> SupportedPassKind; + pub fn LLVMRustPassKind(Pass: PassRef) -> PassKind; pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); @@ -2031,7 +2049,7 @@ extern { pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, CPU: *const c_char, Features: *const c_char, - Model: CodeGenModel, + Model: CodeModel, Reloc: RelocMode, Level: CodeGenOptLevel, UseSoftFP: bool, @@ -2057,7 +2075,8 @@ extern { PM: PassManagerRef, M: ModuleRef, Output: *const c_char, - FileType: FileType) -> bool; + FileType: FileType) + -> LLVMRustResult; pub fn LLVMRustPrintModule(PM: PassManagerRef, M: ModuleRef, Output: *const c_char); @@ -2123,7 +2142,8 @@ extern { NumMembers: size_t, Members: *const RustArchiveMemberRef, WriteSymbtab: bool, - Kind: ArchiveKind) -> c_int; + Kind: ArchiveKind) -> + LLVMRustResult; pub fn LLVMRustArchiveMemberNew(Filename: *const c_char, Name: *const c_char, Child: ArchiveChildRef) -> RustArchiveMemberRef; diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 29019f3683d..e063209799f 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -293,7 +293,7 @@ impl<'a> ArchiveBuilder<'a> { members.as_ptr(), self.should_update_symbols, kind); - let ret = if r != 0 { + let ret = if r.into_result().is_err() { let err = llvm::LLVMRustGetLastError(); let msg = if err.is_null() { "failed to write archive".to_string() diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 87815c63f79..0f3a45a7cff 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -54,7 +54,7 @@ pub fn write_output_file( let output_c = path2cstr(output); let result = llvm::LLVMRustWriteOutputFile( target, pm, m, output_c.as_ptr(), file_type); - if !result { + if result.into_result().is_err() { llvm_err(handler, format!("could not write output to {}", output.display())); } } @@ -138,11 +138,11 @@ fn target_feature(sess: &Session) -> String { fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { match optimize { - config::OptLevel::No => llvm::CodeGenLevelNone, - config::OptLevel::Less => llvm::CodeGenLevelLess, - config::OptLevel::Default => llvm::CodeGenLevelDefault, - config::OptLevel::Aggressive => llvm::CodeGenLevelAggressive, - _ => llvm::CodeGenLevelDefault, + config::OptLevel::No => llvm::CodeGenOptLevel::None, + config::OptLevel::Less => llvm::CodeGenOptLevel::Less, + config::OptLevel::Default => llvm::CodeGenOptLevel::Default, + config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive, + _ => llvm::CodeGenOptLevel::Default, } } @@ -169,11 +169,11 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { }; let code_model = match code_model_arg { - "default" => llvm::CodeModelDefault, - "small" => llvm::CodeModelSmall, - "kernel" => llvm::CodeModelKernel, - "medium" => llvm::CodeModelMedium, - "large" => llvm::CodeModelLarge, + "default" => llvm::CodeModel::Default, + "small" => llvm::CodeModel::Small, + "kernel" => llvm::CodeModel::Kernel, + "medium" => llvm::CodeModel::Medium, + "large" => llvm::CodeModel::Large, _ => { sess.err(&format!("{:?} is not a valid code model", sess.opts @@ -449,9 +449,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, return false; } let pass_manager = match llvm::LLVMRustPassKind(pass) { - llvm::SupportedPassKind::Function => fpm, - llvm::SupportedPassKind::Module => mpm, - llvm::SupportedPassKind::Unsupported => { + llvm::PassKind::Function => fpm, + llvm::PassKind::Module => mpm, + llvm::PassKind::Other => { cgcx.handler.err("Encountered LLVM pass kind we can't handle"); return true }, @@ -579,7 +579,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }; with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(cgcx.handler, tm, cpm, llmod, &path, - llvm::AssemblyFileType); + llvm::FileType::AssemblyFile); }); if config.emit_obj { llvm::LLVMDisposeModule(llmod); @@ -588,7 +588,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if write_obj { with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, llvm::ObjectFileType); + write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, + llvm::FileType::ObjectFile); }); } }); @@ -1078,7 +1079,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_level = config.opt_level.unwrap_or(llvm::CodeGenLevelNone); + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; @@ -1102,7 +1103,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, (_, _, Some(t)) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); } - (llvm::CodeGenLevelAggressive, _, _) => { + (llvm::CodeGenOptLevel::Aggressive, _, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); } (_, llvm::CodeGenOptSizeDefault, _) => { @@ -1111,15 +1112,18 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, (_, llvm::CodeGenOptSizeAggressive, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); } - (llvm::CodeGenLevelNone, _, _) => { + (llvm::CodeGenOptLevel::None, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, false); } - (llvm::CodeGenLevelLess, _, _) => { + (llvm::CodeGenOptLevel::Less, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, true); } - (llvm::CodeGenLevelDefault, _, _) => { + (llvm::CodeGenOptLevel::Default, _, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); } + (llvm::CodeGenOptLevel::Other, _, _) => { + bug!("CodeGenOptLevel::Other selected") + } } f(builder); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 5a3c1c8512a..166ce990fdd 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -325,10 +325,10 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { }; match reloc_model_arg { - "pic" => llvm::RelocPIC, - "static" => llvm::RelocStatic, - "default" => llvm::RelocDefault, - "dynamic-no-pic" => llvm::RelocDynamicNoPic, + "pic" => llvm::RelocMode::PIC, + "static" => llvm::RelocMode::Static, + "default" => llvm::RelocMode::Default, + "dynamic-no-pic" => llvm::RelocMode::DynamicNoPic, _ => { sess.err(&format!("{:?} is not a valid relocation mode", sess.opts @@ -347,7 +347,7 @@ fn is_any_library(sess: &Session) -> bool { } pub fn is_pie_binary(sess: &Session) -> bool { - !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocPIC + !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC } unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 3d48024c879..059cc40d511 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -16,24 +16,62 @@ using namespace llvm; using namespace llvm::object; -struct LLVMRustArchiveMember { +struct RustArchiveMember { const char *filename; const char *name; Archive::Child child; - LLVMRustArchiveMember(): filename(NULL), name(NULL), + RustArchiveMember(): filename(NULL), name(NULL), #if LLVM_VERSION_MINOR >= 8 child(NULL, NULL, NULL) #else child(NULL, NULL) #endif {} - ~LLVMRustArchiveMember() {} + ~RustArchiveMember() {} }; -typedef OwningBinary RustArchive; -extern "C" void* +struct RustArchiveIterator { + Archive::child_iterator cur; + Archive::child_iterator end; +#if LLVM_VERSION_MINOR >= 9 + Error err; +#endif +}; + +enum class LLVMRustArchiveKind { + Other, + GNU, + MIPS64, + BSD, + COFF, +}; + +static Archive::Kind +from_rust(LLVMRustArchiveKind kind) +{ + switch (kind) { + case LLVMRustArchiveKind::GNU: + return Archive::K_GNU; + case LLVMRustArchiveKind::MIPS64: + return Archive::K_MIPS64; + case LLVMRustArchiveKind::BSD: + return Archive::K_BSD; + case LLVMRustArchiveKind::COFF: + return Archive::K_COFF; + default: + abort(); + } +} + +typedef OwningBinary *LLVMRustArchiveRef; +typedef RustArchiveMember *LLVMRustArchiveMemberRef; +typedef Archive::Child *LLVMRustArchiveChildRef; +typedef Archive::Child const *LLVMRustArchiveChildConstRef; +typedef RustArchiveIterator *LLVMRustArchiveIteratorRef; + +extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *path) { ErrorOr> buf_or = MemoryBuffer::getFile(path, -1, @@ -66,20 +104,12 @@ LLVMRustOpenArchive(char *path) { } extern "C" void -LLVMRustDestroyArchive(RustArchive *ar) { +LLVMRustDestroyArchive(LLVMRustArchiveRef ar) { delete ar; } -struct RustArchiveIterator { - Archive::child_iterator cur; - Archive::child_iterator end; -#if LLVM_VERSION_MINOR >= 9 - Error err; -#endif -}; - -extern "C" RustArchiveIterator* -LLVMRustArchiveIteratorNew(RustArchive *ra) { +extern "C" LLVMRustArchiveIteratorRef +LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) { Archive *ar = ra->getBinary(); RustArchiveIterator *rai = new RustArchiveIterator(); #if LLVM_VERSION_MINOR <= 8 @@ -95,8 +125,8 @@ LLVMRustArchiveIteratorNew(RustArchive *ra) { return rai; } -extern "C" const Archive::Child* -LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { +extern "C" LLVMRustArchiveChildConstRef +LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) { #if LLVM_VERSION_MINOR >= 9 if (rai->err) { LLVMRustSetLastError(toString(std::move(rai->err)).c_str()); @@ -122,17 +152,17 @@ LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { } extern "C" void -LLVMRustArchiveChildFree(Archive::Child *child) { +LLVMRustArchiveChildFree(LLVMRustArchiveChildRef child) { delete child; } extern "C" void -LLVMRustArchiveIteratorFree(RustArchiveIterator *rai) { +LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef rai) { delete rai; } extern "C" const char* -LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) { +LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef child, size_t *size) { ErrorOr name_or_err = child->getName(); if (name_or_err.getError()) return NULL; @@ -142,7 +172,7 @@ LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) { } extern "C" const char* -LLVMRustArchiveChildData(Archive::Child *child, size_t *size) { +LLVMRustArchiveChildData(LLVMRustArchiveChildRef child, size_t *size) { StringRef buf; ErrorOr buf_or_err = child->getBuffer(); if (buf_or_err.getError()) { @@ -154,9 +184,10 @@ LLVMRustArchiveChildData(Archive::Child *child, size_t *size) { return buf.data(); } -extern "C" LLVMRustArchiveMember* -LLVMRustArchiveMemberNew(char *Filename, char *Name, Archive::Child *child) { - LLVMRustArchiveMember *Member = new LLVMRustArchiveMember; +extern "C" LLVMRustArchiveMemberRef +LLVMRustArchiveMemberNew(char *Filename, char *Name, + LLVMRustArchiveChildRef child) { + RustArchiveMember *Member = new RustArchiveMember; Member->filename = Filename; Member->name = Name; if (child) @@ -165,22 +196,23 @@ LLVMRustArchiveMemberNew(char *Filename, char *Name, Archive::Child *child) { } extern "C" void -LLVMRustArchiveMemberFree(LLVMRustArchiveMember *Member) { +LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) { delete Member; } -extern "C" int +extern "C" LLVMRustResult LLVMRustWriteArchive(char *Dst, size_t NumMembers, - const LLVMRustArchiveMember **NewMembers, + const LLVMRustArchiveMemberRef *NewMembers, bool WriteSymbtab, - Archive::Kind Kind) { + LLVMRustArchiveKind rust_kind) { #if LLVM_VERSION_MINOR <= 8 std::vector Members; #else std::vector Members; #endif + auto Kind = from_rust(rust_kind); for (size_t i = 0; i < NumMembers; i++) { auto Member = NewMembers[i]; @@ -190,7 +222,7 @@ LLVMRustWriteArchive(char *Dst, Expected MOrErr = NewArchiveMember::getFile(Member->filename, true); if (!MOrErr) { LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); - return -1; + return LLVMRustResult::Failure; } Members.push_back(std::move(*MOrErr)); #elif LLVM_VERSION_MINOR == 8 @@ -205,7 +237,7 @@ LLVMRustWriteArchive(char *Dst, Expected MOrErr = NewArchiveMember::getOldMember(Member->child, true); if (!MOrErr) { LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); - return -1; + return LLVMRustResult::Failure; } Members.push_back(std::move(*MOrErr)); #endif @@ -217,7 +249,7 @@ LLVMRustWriteArchive(char *Dst, auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true); #endif if (!pair.second) - return 0; + return LLVMRustResult::Success; LLVMRustSetLastError(pair.second.message().c_str()); - return -1; + return LLVMRustResult::Failure; } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a1276060271..9e72724d8ab 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -54,41 +54,48 @@ LLVMInitializePasses() { initializeTarget(Registry); } - -enum class SupportedPassKind { +enum class LLVMRustPassKind { + Other, Function, Module, - Unsupported }; -extern "C" Pass* +static LLVMRustPassKind +to_rust(PassKind kind) +{ + switch (kind) { + case PT_Function: + return LLVMRustPassKind::Function; + case PT_Module: + return LLVMRustPassKind::Module; + default: + return LLVMRustPassKind::Other; + } +} + +extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) { StringRef SR(PassName); PassRegistry *PR = PassRegistry::getPassRegistry(); const PassInfo *PI = PR->getPassInfo(SR); if (PI) { - return PI->createPass(); + return wrap(PI->createPass()); } return NULL; } -extern "C" SupportedPassKind -LLVMRustPassKind(Pass *pass) { - assert(pass); - PassKind passKind = pass->getPassKind(); - if (passKind == PT_Module) { - return SupportedPassKind::Module; - } else if (passKind == PT_Function) { - return SupportedPassKind::Function; - } else { - return SupportedPassKind::Unsupported; - } +extern "C" LLVMRustPassKind +LLVMRustPassKind(LLVMPassRef rust_pass) { + assert(rust_pass); + Pass *pass = unwrap(rust_pass); + return to_rust(pass->getPassKind()); } extern "C" void -LLVMRustAddPass(LLVMPassManagerRef PM, Pass *pass) { - assert(pass); +LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { + assert(rust_pass); + Pass *pass = unwrap(rust_pass); PassManagerBase *pm = unwrap(PM); pm->add(pass); } @@ -162,13 +169,69 @@ LLVMRustHasFeature(LLVMTargetMachineRef TM, return (Bits & FeatureEntry->Value) == FeatureEntry->Value; } +enum class LLVMRustCodeModel { + Other, + Default, + JITDefault, + Small, + Kernel, + Medium, + Large, +}; + +static CodeModel::Model +from_rust(LLVMRustCodeModel model) +{ + switch (model) { + case LLVMRustCodeModel::Default: + return CodeModel::Default; + case LLVMRustCodeModel::JITDefault: + return CodeModel::JITDefault; + case LLVMRustCodeModel::Small: + return CodeModel::Small; + case LLVMRustCodeModel::Kernel: + return CodeModel::Kernel; + case LLVMRustCodeModel::Medium: + return CodeModel::Medium; + case LLVMRustCodeModel::Large: + return CodeModel::Large; + default: + abort(); + } +} + +enum class LLVMRustCodeGenOptLevel { + Other, + None, + Less, + Default, + Aggressive, +}; + +static CodeGenOpt::Level +from_rust(LLVMRustCodeGenOptLevel level) +{ + switch (level) { + case LLVMRustCodeGenOptLevel::None: + return CodeGenOpt::None; + case LLVMRustCodeGenOptLevel::Less: + return CodeGenOpt::Less; + case LLVMRustCodeGenOptLevel::Default: + return CodeGenOpt::Default; + case LLVMRustCodeGenOptLevel::Aggressive: + return CodeGenOpt::Aggressive; + default: + abort(); + } +} + extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(const char *triple, const char *cpu, const char *feature, - CodeModel::Model CM, + LLVMRustCodeModel rust_CM, LLVMRelocMode Reloc, - CodeGenOpt::Level OptLevel, + LLVMRustCodeGenOptLevel rust_OptLevel, bool UseSoftFloat, bool PositionIndependentExecutable, bool FunctionSections, @@ -179,6 +242,9 @@ LLVMRustCreateTargetMachine(const char *triple, #else Optional RM; #endif + auto CM = from_rust(rust_CM); + auto OptLevel = from_rust(rust_OptLevel); + switch (Reloc){ case LLVMRelocStatic: RM = Reloc::Static; @@ -251,14 +317,14 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, extern "C" void LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB, - CodeGenOpt::Level OptLevel, + LLVMRustCodeGenOptLevel OptLevel, bool MergeFunctions, bool SLPVectorize, bool LoopVectorize) { // Ignore mergefunc for now as enabling it causes crashes. //unwrap(PMB)->MergeFunctions = MergeFunctions; unwrap(PMB)->SLPVectorize = SLPVectorize; - unwrap(PMB)->OptLevel = OptLevel; + unwrap(PMB)->OptLevel = from_rust(OptLevel); unwrap(PMB)->LoopVectorize = LoopVectorize; } @@ -314,13 +380,33 @@ LLVMRustSetLLVMOptions(int Argc, char **Argv) { cl::ParseCommandLineOptions(Argc, Argv); } -extern "C" bool +enum class LLVMRustFileType { + Other, + AssemblyFile, + ObjectFile, +}; + +static TargetMachine::CodeGenFileType +from_rust(LLVMRustFileType type) +{ + switch (type) { + case LLVMRustFileType::AssemblyFile: + return TargetMachine::CGFT_AssemblyFile; + case LLVMRustFileType::ObjectFile: + return TargetMachine::CGFT_ObjectFile; + default: + abort(); + } +} + +extern "C" LLVMRustResult LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, LLVMModuleRef M, const char *path, - TargetMachine::CodeGenFileType FileType) { + LLVMRustFileType rust_FileType) { llvm::legacy::PassManager *PM = unwrap(PMR); + auto FileType = from_rust(rust_FileType); std::string ErrorInfo; std::error_code EC; @@ -329,7 +415,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, ErrorInfo = EC.message(); if (ErrorInfo != "") { LLVMRustSetLastError(ErrorInfo.c_str()); - return false; + return LLVMRustResult::Failure; } unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false); @@ -339,7 +425,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, // stream (OS), so the only real safe place to delete this is here? Don't we // wish this was written in Rust? delete PM; - return true; + return LLVMRustResult::Success; } extern "C" void diff --git a/src/rustllvm/README b/src/rustllvm/README index c0db3f68a76..e1c6dd07d2b 100644 --- a/src/rustllvm/README +++ b/src/rustllvm/README @@ -1,2 +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. diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 2a47e8b0895..5aae11fb456 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -58,6 +58,11 @@ void LLVMRustSetLastError(const char*); +enum class LLVMRustResult { + Success, + Failure +}; + typedef struct OpaqueRustString *RustStringRef; typedef struct LLVMOpaqueTwine *LLVMTwineRef; typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef;