├── .gitignore ├── lib └── llvm │ ├── src │ ├── lib.rs │ ├── reloc_sink.rs │ ├── string_table.rs │ ├── context.rs │ ├── module.rs │ ├── types.rs │ ├── translate.rs │ └── operations.rs │ └── Cargo.toml ├── Cargo.toml ├── src ├── utils.rs ├── llvm2cranelift.rs └── llvm.rs ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *.bk 2 | *.swp 3 | *.swo 4 | tags 5 | target 6 | Cargo.lock 7 | .*.rustfmt 8 | cranelift.dbg* 9 | rusty-tags.* 10 | -------------------------------------------------------------------------------- /lib/llvm/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Translator from LLVM IR to Cranelift IL. 2 | 3 | #![deny(missing_docs)] 4 | 5 | extern crate cranelift_codegen; 6 | extern crate cranelift_frontend; 7 | extern crate fnv; 8 | extern crate indexmap; 9 | extern crate libc; 10 | extern crate llvm_sys; 11 | 12 | mod context; 13 | mod module; 14 | mod operations; 15 | mod reloc_sink; 16 | mod string_table; 17 | mod translate; 18 | mod types; 19 | 20 | pub use module::SymbolKind; 21 | pub use translate::{create_llvm_context, read_llvm, translate_module}; 22 | -------------------------------------------------------------------------------- /lib/llvm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cranelift-llvm" 3 | version = "0.0.0" 4 | authors = ["The Cranelift Project Developers"] 5 | publish = false 6 | description = "Translator from LLVM IR to Cranelift IL" 7 | repository = "https://github.com/sunfishcode/cranelift" 8 | license = "Apache-2.0 WITH LLVM-exception" 9 | 10 | [lib] 11 | name = "cranelift_llvm" 12 | 13 | [dependencies] 14 | cranelift-codegen = "0.42.0" 15 | cranelift-frontend = "0.42.0" 16 | fnv = "1.0.6" 17 | llvm-sys = "50.0.3" 18 | libc = "0.2.36" 19 | indexmap = "0.4.1" 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "llvm2cranelift-tools" 3 | version = "0.0.0" 4 | authors = ["The Cranelift Project Developers"] 5 | publish = false 6 | repository = "https://github.com/sunfishcode/llvm2cranelift" 7 | license = "Apache-2.0 WITH LLVM-exception" 8 | 9 | [[bin]] 10 | name = "llvm2cranelift" 11 | path = "src/llvm2cranelift.rs" 12 | 13 | [dependencies] 14 | cranelift-llvm = { path = "lib/llvm" } 15 | cranelift-codegen = "0.42.0" 16 | cranelift-reader = "0.42.0" 17 | target-lexicon = "0.8.1" 18 | docopt = "0.8.3" 19 | serde = "1.0.27" 20 | serde_derive = "1.0.27" 21 | term = "0.6.1" 22 | faerie = "0.11.0" 23 | goblin = "0.0.14" 24 | 25 | [workspace] 26 | -------------------------------------------------------------------------------- /lib/llvm/src/reloc_sink.rs: -------------------------------------------------------------------------------- 1 | use cranelift_codegen::binemit; 2 | use cranelift_codegen::ir; 3 | 4 | pub struct RelocSink { 5 | pub relocs: Vec<( 6 | binemit::Reloc, 7 | ir::ExternalName, 8 | binemit::CodeOffset, 9 | binemit::Addend, 10 | )>, 11 | } 12 | 13 | impl RelocSink { 14 | pub fn new() -> Self { 15 | Self { relocs: Vec::new() } 16 | } 17 | } 18 | 19 | impl<'func> binemit::RelocSink for RelocSink { 20 | fn reloc_ebb( 21 | &mut self, 22 | _offset: binemit::CodeOffset, 23 | _reloc: binemit::Reloc, 24 | _ebb_offset: binemit::CodeOffset, 25 | ) { 26 | panic!("ebb header addresses not yet implemented"); 27 | } 28 | 29 | fn reloc_external( 30 | &mut self, 31 | offset: binemit::CodeOffset, 32 | reloc: binemit::Reloc, 33 | name: &ir::ExternalName, 34 | addend: binemit::Addend, 35 | ) { 36 | // TODO: How should addend be handled? Should it be added to 37 | // offset and stored in self.relocs or carried through beside 38 | // offset? 39 | self.relocs.push((reloc, name.clone(), offset, addend)); 40 | } 41 | 42 | fn reloc_constant(&mut self, _: binemit::CodeOffset, _: binemit::Reloc, _: ir::ConstantOffset) { 43 | panic!("reloc_constant not yet implemented"); 44 | } 45 | 46 | fn reloc_jt( 47 | &mut self, 48 | _offset: binemit::CodeOffset, 49 | _reloc: binemit::Reloc, 50 | _jt: ir::JumpTable, 51 | ) { 52 | panic!("jump table addresses not yet implemented"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/llvm/src/string_table.rs: -------------------------------------------------------------------------------- 1 | use cranelift_codegen::ir; 2 | use fnv::FnvBuildHasher; 3 | use indexmap::IndexMap; 4 | 5 | type FnvIndexSet = IndexMap; 6 | 7 | pub struct StringTable { 8 | names: FnvIndexSet, 9 | } 10 | 11 | impl StringTable { 12 | pub fn new() -> Self { 13 | Self { 14 | names: FnvIndexSet::default(), 15 | } 16 | } 17 | 18 | /// Return the string name for a given cranelift `ExternalName`. 19 | pub fn get_str(&self, extname: &ir::ExternalName) -> &str { 20 | match *extname { 21 | ir::ExternalName::User { namespace, index } => { 22 | debug_assert!(namespace == 0, "alternate namespaces not yet implemented"); 23 | self.names 24 | .get_index(index as usize) 25 | .expect("name has not yet been declared") 26 | .0 27 | .as_str() 28 | } 29 | _ => panic!("non-user names not yet implemented"), 30 | } 31 | } 32 | 33 | /// Enter a string name into the table. 34 | pub fn declare_extname>(&mut self, string: S) { 35 | let previous = self.names.insert(string.into(), ()); 36 | debug_assert!(previous.is_none()); 37 | } 38 | 39 | /// Return the cranelift `ExternalName` for a given string name. 40 | pub fn get_extname>(&self, string: S) -> ir::ExternalName { 41 | let index = self.names.get_full(&string.into()).unwrap().0; 42 | debug_assert!(index as u32 as usize == index); 43 | ir::ExternalName::user(0, index as u32) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/llvm/src/context.rs: -------------------------------------------------------------------------------- 1 | //! Translation state. 2 | 3 | use cranelift_codegen::ir; 4 | use cranelift_frontend; 5 | use cranelift_frontend::Variable; 6 | use llvm_sys::prelude::*; 7 | use llvm_sys::target::*; 8 | use std::collections::HashMap; 9 | 10 | /// Information about Ebbs that we'll create. 11 | pub struct EbbInfo { 12 | pub num_preds_left: usize, 13 | } 14 | 15 | impl Default for EbbInfo { 16 | fn default() -> Self { 17 | Self { num_preds_left: 0 } 18 | } 19 | } 20 | 21 | /// Data structures used throughout translation. 22 | pub struct Context<'a> { 23 | /// Builder for emitting instructions. 24 | pub builder: cranelift_frontend::FunctionBuilder<'a>, 25 | 26 | /// Map from LLVM Values to `Variable`s. 27 | pub value_map: HashMap, 28 | 29 | /// Map from LLVM BasicBlocks to bookkeeping data. 30 | pub ebb_info: HashMap, 31 | 32 | /// Map from LLVM BasicBlocks to Cranelift `Ebb`s. Only contains entries for 33 | /// blocks that correspond to `Ebb` headers. 34 | pub ebb_map: HashMap, 35 | 36 | /// The LLVM DataLayout (formerly known as TargetData, the name still used 37 | /// in the C API). 38 | pub dl: LLVMTargetDataRef, 39 | } 40 | 41 | impl<'a> Context<'a> { 42 | pub fn new( 43 | func: &'a mut ir::Function, 44 | il_builder: &'a mut cranelift_frontend::FunctionBuilderContext, 45 | dl: LLVMTargetDataRef, 46 | ) -> Self { 47 | Self { 48 | builder: cranelift_frontend::FunctionBuilder::new(func, il_builder), 49 | value_map: HashMap::new(), 50 | ebb_info: HashMap::new(), 51 | ebb_map: HashMap::new(), 52 | dl, 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions. 2 | 3 | use cranelift_codegen::isa; 4 | use cranelift_codegen::isa::TargetIsa; 5 | use cranelift_codegen::settings::{self, FlagsOrIsa}; 6 | use cranelift_reader::{parse_options, Location}; 7 | use std::str::FromStr; 8 | use target_lexicon::Triple; 9 | 10 | /// Like `FlagsOrIsa`, but holds ownership. 11 | pub enum OwnedFlagsOrIsa { 12 | Flags(settings::Flags), 13 | Isa(Box), 14 | } 15 | 16 | impl OwnedFlagsOrIsa { 17 | /// Produce a FlagsOrIsa reference. 18 | pub fn as_fisa(&self) -> FlagsOrIsa { 19 | match *self { 20 | OwnedFlagsOrIsa::Flags(ref flags) => FlagsOrIsa::from(flags), 21 | OwnedFlagsOrIsa::Isa(ref isa) => FlagsOrIsa::from(&**isa), 22 | } 23 | } 24 | } 25 | 26 | /// Parse "set" and "triple" commands. 27 | pub fn parse_sets_and_triple( 28 | flag_set: &[String], 29 | flag_triple: &str, 30 | ) -> Result { 31 | let mut flag_builder = settings::builder(); 32 | parse_options( 33 | flag_set.iter().map(|x| x.as_str()), 34 | &mut flag_builder, 35 | Location { line_number: 0 }, 36 | ).map_err(|err| err.to_string())?; 37 | 38 | let mut words = flag_triple.trim().split_whitespace(); 39 | // Look for `target foo`. 40 | if let Some(triple_name) = words.next() { 41 | let triple = match Triple::from_str(triple_name) { 42 | Ok(triple) => triple, 43 | Err(parse_error) => return Err(parse_error.to_string()), 44 | }; 45 | let mut isa_builder = isa::lookup(triple).map_err(|err| match err { 46 | isa::LookupError::SupportDisabled => { 47 | format!("support for triple '{}' is disabled", triple_name) 48 | } 49 | isa::LookupError::Unsupported => format!( 50 | "support for triple '{}' is not implemented yet", 51 | triple_name 52 | ), 53 | })?; 54 | // Apply the ISA-specific settings to `isa_builder`. 55 | parse_options(words, &mut isa_builder, Location { line_number: 0 }) 56 | .map_err(|err| err.to_string())?; 57 | 58 | Ok(OwnedFlagsOrIsa::Isa( 59 | isa_builder.finish(settings::Flags::new(flag_builder)), 60 | )) 61 | } else { 62 | Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(flag_builder))) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/llvm2cranelift.rs: -------------------------------------------------------------------------------- 1 | //! llvm2cranelift driver program. 2 | 3 | extern crate cranelift_codegen; 4 | extern crate cranelift_llvm; 5 | extern crate cranelift_reader; 6 | extern crate docopt; 7 | extern crate target_lexicon; 8 | extern crate term; 9 | #[macro_use] 10 | extern crate serde_derive; 11 | extern crate faerie; 12 | extern crate goblin; 13 | 14 | use cranelift_codegen::VERSION; 15 | use docopt::Docopt; 16 | use std::io::{self, Write}; 17 | use std::process; 18 | 19 | mod llvm; 20 | mod utils; 21 | 22 | const USAGE: &str = " 23 | Cranelift code generator utility 24 | 25 | Usage: 26 | llvm2cranelift -p [-v] [--set ]... [--isa ] ... 27 | llvm2cranelift [-v] [--set ]... [--isa ] -o ... 28 | llvm2cranelift --help | --version 29 | 30 | Options: 31 | -v, --verbose be more verbose 32 | -p, --print print the resulting Cranelift IL 33 | -h, --help print this help message 34 | --set= configure Cranelift settings 35 | --isa= specify the Cranelift ISA 36 | -o, --output specify the output file 37 | --version print the Cranelift version 38 | 39 | "; 40 | 41 | #[derive(Deserialize, Debug)] 42 | struct Args { 43 | arg_file: Vec, 44 | arg_output: String, 45 | flag_print: bool, 46 | flag_verbose: bool, 47 | flag_set: Vec, 48 | flag_isa: String, 49 | } 50 | 51 | /// A command either succeeds or fails with an error message. 52 | pub type CommandResult = Result<(), String>; 53 | 54 | /// Parse the command line arguments and run the requested command. 55 | fn clif_util() -> CommandResult { 56 | // Parse command line arguments. 57 | let args: Args = Docopt::new(USAGE) 58 | .and_then(|d| { 59 | d.help(true) 60 | .version(Some(format!("Cranelift {}", VERSION))) 61 | .deserialize() 62 | }) 63 | .unwrap_or_else(|e| e.exit()); 64 | 65 | llvm::run( 66 | args.arg_file, 67 | &args.arg_output, 68 | args.flag_verbose, 69 | args.flag_print, 70 | args.flag_set, 71 | args.flag_isa, 72 | ) 73 | } 74 | 75 | fn main() { 76 | if let Err(mut msg) = clif_util() { 77 | if !msg.ends_with('\n') { 78 | msg.push('\n'); 79 | } 80 | io::stdout().flush().expect("flushing stdout"); 81 | io::stderr().write_all(msg.as_bytes()).unwrap(); 82 | process::exit(1); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/llvm/src/module.rs: -------------------------------------------------------------------------------- 1 | use cranelift_codegen::ir; 2 | use cranelift_codegen::isa::TargetIsa; 3 | use std::fmt; 4 | 5 | use reloc_sink::RelocSink; 6 | use string_table::StringTable; 7 | 8 | /// The kind of symbol, either data or function. 9 | #[derive(PartialEq, Eq, Debug, Clone, Copy)] 10 | pub enum SymbolKind { 11 | /// Data symbol 12 | Data, 13 | /// Function symbol 14 | Function, 15 | } 16 | 17 | pub struct DataSymbol { 18 | pub name: ir::ExternalName, 19 | pub contents: Vec, 20 | } 21 | 22 | impl fmt::Display for DataSymbol { 23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 24 | write!(f, "{}: ", self.name,)?; 25 | for byte in &self.contents { 26 | write!(f, "0x{:02x}, ", byte)?; 27 | } 28 | Ok(()) 29 | } 30 | } 31 | 32 | pub struct Compilation { 33 | pub body: Vec, 34 | pub relocs: RelocSink, 35 | } 36 | 37 | pub struct CompiledFunction { 38 | pub il: ir::Function, 39 | pub compilation: Option, 40 | } 41 | 42 | impl CompiledFunction { 43 | pub fn display<'a>(&'a self, isa: Option<&'a TargetIsa>) -> DisplayCompiledFunction<'a> { 44 | DisplayCompiledFunction { 45 | compiled_func: &self, 46 | isa, 47 | } 48 | } 49 | } 50 | 51 | pub struct DisplayCompiledFunction<'a> { 52 | compiled_func: &'a CompiledFunction, 53 | isa: Option<&'a TargetIsa>, 54 | } 55 | 56 | impl<'a> fmt::Display for DisplayCompiledFunction<'a> { 57 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 58 | write!(f, "{}", self.compiled_func.il.display(self.isa),)?; 59 | if let Some(ref compilation) = self.compiled_func.compilation { 60 | for byte in &compilation.body { 61 | write!(f, "0x{:02x}, ", byte)?; 62 | } 63 | write!(f, "\n")?; 64 | for &(ref reloc, ref name, ref offset, addend) in &compilation.relocs.relocs { 65 | match addend { 66 | 0 => write!(f, "reloc: {}:{}@{}\n", reloc, name, offset)?, 67 | _ => write!(f, "reloc: {}:{}{}@{}\n", reloc, name, addend, offset)?, 68 | } 69 | } 70 | } 71 | Ok(()) 72 | } 73 | } 74 | 75 | pub struct Module { 76 | pub functions: Vec, 77 | pub data_symbols: Vec, 78 | pub imports: Vec<(ir::ExternalName, SymbolKind)>, 79 | pub strings: StringTable, 80 | } 81 | 82 | impl Module { 83 | pub fn new() -> Self { 84 | Self { 85 | functions: Vec::new(), 86 | data_symbols: Vec::new(), 87 | imports: Vec::new(), 88 | strings: StringTable::new(), 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # llvm2cranelift 2 | LLVM IR to Cranelift translator 3 | 4 | This is a work in progress which currently is complete enough to be usable as a 5 | testing and demonstration tool. It supports all the basic integer, floating-point 6 | control flow, call, and memory operations, and more. 7 | 8 | Here's a quick example of it in action: 9 | 10 | ``` 11 | $ cat test.ll 12 | define void @foo(i32 %arg, i32 %arg1) { 13 | bb: 14 | %tmp = icmp ult i32 %arg, 4 15 | %tmp2 = icmp eq i32 %arg1, 0 16 | %tmp3 = or i1 %tmp2, %tmp 17 | br i1 %tmp3, label %bb4, label %bb6 18 | 19 | bb4: 20 | %tmp5 = call i32 @bar() 21 | ret void 22 | 23 | bb6: 24 | ret void 25 | } 26 | 27 | declare i32 @bar() 28 | 29 | $ llvm2cranelift -p test.ll 30 | ; foo 31 | function u0:0(i32, i32) native { 32 | sig0 = () -> i32 native 33 | fn0 = sig0 u0:1 34 | 35 | ebb1(v0: i32, v1: i32): 36 | v2 = icmp_imm ult v0, 4 37 | v3 = icmp_imm eq v1, 0 38 | v4 = bor v3, v2 39 | brz v4, ebb0 40 | v5 = call fn0() 41 | return 42 | 43 | ebb0: 44 | return 45 | } 46 | ``` 47 | 48 | Features not yet implemented, but which could be reasonably implemented include: 49 | - switch instructions with non-sequential cases 50 | - first-class aggregates 51 | - SIMD types and operations 52 | - most function argument attributes 53 | - integer types with unusual sizes 54 | - indirectbr 55 | 56 | Features not yet implemented that would require features that Cranelift does not 57 | yet fully implement include: 58 | - exception handling (invoke, landingpad, etc.) 59 | - dynamic alloca 60 | - atomic operations 61 | - thread-local globals 62 | - volatile operations 63 | - add-with-overflow intrinsics 64 | - inline asm 65 | - GC hooks 66 | - varargs 67 | - ifuncs 68 | - comdat groups 69 | 70 | Features not yet implemented that LLVM's C API does not yet sufficiently expose: 71 | - global aliases 72 | - debug source locations for instructions 73 | - debug info 74 | 75 | Optimizations that are commonly done for LLVM IR during codegen that aren't yet 76 | implemented include: 77 | - Optimize @llvm.memcpy et al for small and/or aligned cases. 78 | - Optimize switch for small, sparse, and/or other special cases. 79 | - Pattern-match operations that are not present in LLVM IR, such as 80 | rotates, load/store offsets, wrapping/extending loads and stores, 81 | `br_icmp`, etc. 82 | - Expand @llvm.powi with small integer constants into efficient sequences. 83 | - Handling of i1 is suboptimal in cases like zext(load(p)) because the result 84 | of the load is converted to boolean and then converted back. 85 | 86 | Also of note is that it doesn't currently translate LLVM's PHIs, SSA uses, and 87 | SSA defs directly into Cranelift; it instead just reports uses and defs to 88 | Cranelift's SSA builder, which then builds its own SSA form. That simplifies 89 | handling of basic blocks that aren't in RPO -- in layout order, we may see uses 90 | before we see their defs. 91 | 92 | ### Contribution 93 | 94 | Unless you explicitly state otherwise, any contribution intentionally submitted 95 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any 96 | additional terms or conditions. 97 | -------------------------------------------------------------------------------- /lib/llvm/src/types.rs: -------------------------------------------------------------------------------- 1 | //! Translate types from LLVM IR to Cranelift IL. 2 | 3 | use cranelift_codegen::ir; 4 | use cranelift_codegen::isa::CallConv; 5 | use llvm_sys::core::*; 6 | use llvm_sys::prelude::*; 7 | use llvm_sys::target::*; 8 | use llvm_sys::LLVMTypeKind::*; 9 | use std::ptr; 10 | 11 | /// Return a Cranelift integer type with the given bit width. 12 | pub fn translate_integer_type(bitwidth: usize) -> ir::Type { 13 | match bitwidth { 14 | 1 => ir::types::B1, 15 | 8 => ir::types::I8, 16 | 16 => ir::types::I16, 17 | 32 => ir::types::I32, 18 | 64 => ir::types::I64, 19 | width => panic!("unimplemented integer bit width {}", width), 20 | } 21 | } 22 | 23 | /// Return the Cranelift integer type for a pointer. 24 | pub fn translate_pointer_type(dl: LLVMTargetDataRef) -> ir::Type { 25 | translate_integer_type(unsafe { LLVMPointerSize(dl) * 8 } as usize) 26 | } 27 | 28 | /// Translate an LLVM first-class type into a Cranelift type. 29 | pub fn translate_type(llvm_ty: LLVMTypeRef, dl: LLVMTargetDataRef) -> ir::Type { 30 | match unsafe { LLVMGetTypeKind(llvm_ty) } { 31 | LLVMVoidTypeKind => ir::types::INVALID, 32 | LLVMHalfTypeKind => panic!("unimplemented: f16 type"), 33 | LLVMFloatTypeKind => ir::types::F32, 34 | LLVMDoubleTypeKind => ir::types::F64, 35 | LLVMX86_FP80TypeKind => panic!("unimplemented: x86_fp80 type"), 36 | LLVMFP128TypeKind => panic!("unimplemented: f128 type"), 37 | LLVMPPC_FP128TypeKind => panic!("unimplemented: double double type"), 38 | LLVMLabelTypeKind => panic!("unimplemented: label types"), 39 | LLVMIntegerTypeKind => { 40 | translate_integer_type(unsafe { LLVMGetIntTypeWidth(llvm_ty) } as usize) 41 | } 42 | LLVMFunctionTypeKind => panic!("use translate_sig to translate function types"), 43 | LLVMStructTypeKind => panic!("unimplemented: first-class struct types"), 44 | LLVMArrayTypeKind => panic!("unimplemented: first-class array types"), 45 | LLVMPointerTypeKind => { 46 | if unsafe { LLVMGetPointerAddressSpace(llvm_ty) } != 0 { 47 | panic!("unimplemented: non-default address spaces"); 48 | } 49 | translate_pointer_type(dl) 50 | } 51 | LLVMVectorTypeKind => panic!("unimplemented: vector types"), 52 | LLVMMetadataTypeKind => panic!("attempted to translate a metadata type"), 53 | LLVMX86_MMXTypeKind => panic!("unimplemented: MMX type"), 54 | LLVMTokenTypeKind => panic!("unimplemented: token types"), 55 | } 56 | } 57 | 58 | /// Translate an LLVM function type into a Cranelift signature. 59 | pub fn translate_sig(llvm_ty: LLVMTypeRef, dl: LLVMTargetDataRef) -> ir::Signature { 60 | debug_assert_eq!(unsafe { LLVMGetTypeKind(llvm_ty) }, LLVMFunctionTypeKind); 61 | 62 | // TODO: Translate the calling convention. 63 | let mut sig = ir::Signature::new(CallConv::SystemV); 64 | 65 | let num_llvm_params = unsafe { LLVMCountParamTypes(llvm_ty) } as usize; 66 | let mut llvm_params: Vec = Vec::with_capacity(num_llvm_params); 67 | llvm_params.resize(num_llvm_params, ptr::null_mut()); 68 | 69 | // TODO: First-class aggregate params and return values. 70 | 71 | unsafe { LLVMGetParamTypes(llvm_ty, llvm_params.as_mut_ptr()) }; 72 | let mut params: Vec = Vec::with_capacity(num_llvm_params); 73 | for llvm_param in &llvm_params { 74 | params.push(ir::AbiParam::new(translate_type(*llvm_param, dl))); 75 | } 76 | sig.params = params; 77 | 78 | let mut returns: Vec = Vec::with_capacity(1); 79 | match translate_type(unsafe { LLVMGetReturnType(llvm_ty) }, dl) { 80 | ir::types::INVALID => {} 81 | ty => returns.push(ir::AbiParam::new(ty)), 82 | } 83 | sig.returns = returns; 84 | 85 | sig 86 | } 87 | -------------------------------------------------------------------------------- /src/llvm.rs: -------------------------------------------------------------------------------- 1 | //! CLI tool to use the functions provided by the [cranelift-llvm](../cranelift_llvm/index.html) crate. 2 | //! 3 | //! Reads LLVM IR files, translates the functions' code to Cranelift IL. 4 | 5 | use cranelift_codegen::binemit::Reloc; 6 | use cranelift_codegen::isa::TargetIsa; 7 | use cranelift_llvm::{create_llvm_context, read_llvm, translate_module, SymbolKind}; 8 | use faerie::{Artifact, Decl, ImportKind, Link}; 9 | use goblin::elf; 10 | use std::fmt::format; 11 | use std::path::Path; 12 | use std::path::PathBuf; 13 | use std::str; 14 | use term; 15 | use utils::{parse_sets_and_triple, OwnedFlagsOrIsa}; 16 | 17 | macro_rules! vprintln { 18 | ($x: expr, $($tts:tt)*) => { 19 | if $x { 20 | println!($($tts)*); 21 | } 22 | } 23 | } 24 | 25 | macro_rules! vprint { 26 | ($x: expr, $($tts:tt)*) => { 27 | if $x { 28 | print!($($tts)*); 29 | } 30 | } 31 | } 32 | 33 | pub fn run( 34 | files: Vec, 35 | arg_output: &str, 36 | flag_verbose: bool, 37 | flag_print: bool, 38 | mut flag_set: Vec, 39 | flag_isa: String, 40 | ) -> Result<(), String> { 41 | // Enable the verifier by default, since we're reading IL in from a 42 | // text file. 43 | flag_set.insert(0, "enable_verifier=1".to_string()); 44 | 45 | let parsed = parse_sets_and_triple(&flag_set, &flag_isa)?; 46 | 47 | for filename in files { 48 | let path = Path::new(&filename); 49 | let name = String::from(path.as_os_str().to_string_lossy()); 50 | handle_module( 51 | arg_output, 52 | flag_verbose, 53 | flag_print, 54 | path.to_path_buf(), 55 | name, 56 | &parsed, 57 | )?; 58 | } 59 | Ok(()) 60 | } 61 | 62 | fn handle_module( 63 | arg_output: &str, 64 | flag_verbose: bool, 65 | flag_print: bool, 66 | path: PathBuf, 67 | name: String, 68 | parsed: &OwnedFlagsOrIsa, 69 | ) -> Result<(), String> { 70 | let mut terminal = term::stdout().unwrap(); 71 | terminal.fg(term::color::YELLOW).unwrap(); 72 | vprint!(flag_verbose, "Handling: "); 73 | terminal.reset().unwrap(); 74 | vprintln!(flag_verbose, "\"{}\"", name); 75 | terminal.fg(term::color::MAGENTA).unwrap(); 76 | vprint!(flag_verbose, "Translating... "); 77 | terminal.reset().unwrap(); 78 | 79 | // If we have an isa from the command-line, use that. Otherwise if the 80 | // file contins a unique isa, use that. 81 | let isa = parsed.as_fisa().isa; 82 | 83 | let ctx = create_llvm_context(); 84 | let llvm_module = read_llvm(ctx, path.to_str().ok_or_else(|| "invalid utf8 in path")?)?; 85 | let module = translate_module(llvm_module, isa)?; 86 | 87 | if flag_print { 88 | vprintln!(flag_verbose, ""); 89 | for func in &module.functions { 90 | println!("; {}", module.strings.get_str(&func.il.name)); 91 | println!("{}", func.display(isa)); 92 | vprintln!(flag_verbose, ""); 93 | } 94 | for sym in &module.data_symbols { 95 | println!("data symbol: {}", sym); 96 | } 97 | } else { 98 | let isa: &TargetIsa = isa.expect("compilation requires a target isa"); 99 | 100 | let mut obj = Artifact::new(isa.triple().clone(), String::from(arg_output)); 101 | 102 | for import in &module.imports { 103 | obj.import( 104 | module.strings.get_str(&import.0), 105 | translate_symbolkind(import.1), 106 | ).expect("faerie import"); 107 | } 108 | for func in &module.functions { 109 | // FIXME: non-global functions. 110 | obj.declare( 111 | module.strings.get_str(&func.il.name), 112 | Decl::function().global(), 113 | ).expect("faerie declare"); 114 | } 115 | // FIXME: non-global and non-writeable data. 116 | for data in &module.data_symbols { 117 | obj.declare( 118 | module.strings.get_str(&data.name), 119 | faerie::Decl::data().global().with_writable(true), 120 | ).expect("faerie declare"); 121 | } 122 | for func in module.functions { 123 | let func_name = module.strings.get_str(&func.il.name); 124 | let compilation = func.compilation.unwrap(); 125 | obj.define(&func_name, compilation.body) 126 | .expect("faerie define"); 127 | // TODO: reloc should derive from Copy 128 | for &(ref reloc, ref external_name, offset, addend) in &compilation.relocs.relocs { 129 | // FIXME: What about other types of relocs? 130 | // TODO: Faerie API: Seems like it might be inefficient to 131 | // identify the caller by name each time. 132 | // TODO: Faerie API: It's inconvenient to keep track of which 133 | // symbols are imports and which aren't. 134 | debug_assert!(addend as i32 as i64 == addend); 135 | let addend = addend as i32; 136 | let name = module.strings.get_str(external_name); 137 | obj.link_with( 138 | Link { 139 | from: &func_name, 140 | to: &name, 141 | at: u64::from(offset), 142 | }, 143 | faerie::Reloc::Raw { 144 | reloc: translate_reloc(reloc), 145 | addend: addend, 146 | }, 147 | ).expect("faerie link"); 148 | } 149 | } 150 | for data in module.data_symbols { 151 | let data_name = module.strings.get_str(&data.name); 152 | obj.define(data_name, data.contents.clone()) 153 | .expect("faerie define"); 154 | } 155 | 156 | let file = ::std::fs::File::create(Path::new(arg_output)) 157 | .map_err(|x| format(format_args!("{}", x)))?; 158 | 159 | // FIXME: Make the format a parameter. 160 | obj.write(file).map_err(|x| format(format_args!("{}", x)))?; 161 | } 162 | 163 | terminal.fg(term::color::GREEN).unwrap(); 164 | vprintln!(flag_verbose, "ok"); 165 | terminal.reset().unwrap(); 166 | Ok(()) 167 | } 168 | 169 | // TODO: Reloc should by Copy 170 | fn translate_reloc(reloc: &Reloc) -> u32 { 171 | match *reloc { 172 | Reloc::X86PCRel4 => elf::reloc::R_X86_64_PC32, 173 | Reloc::Abs4 => elf::reloc::R_X86_64_32, 174 | Reloc::Abs8 => elf::reloc::R_X86_64_64, 175 | Reloc::X86GOTPCRel4 => elf::reloc::R_X86_64_GOTPCREL, 176 | Reloc::X86CallPLTRel4 => elf::reloc::R_X86_64_PLT32, 177 | _ => panic!("unsupported reloc kind"), 178 | } 179 | } 180 | 181 | fn translate_symbolkind(kind: SymbolKind) -> ImportKind { 182 | match kind { 183 | SymbolKind::Function => ImportKind::Function, 184 | SymbolKind::Data => ImportKind::Data, 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | 205 | --- LLVM Exceptions to the Apache 2.0 License ---- 206 | 207 | As an exception, if, as a result of your compiling your source code, portions 208 | of this Software are embedded into an Object form of such source code, you 209 | may redistribute such embedded portions in such Object form without complying 210 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. 211 | 212 | In addition, if you combine or link compiled forms of this Software with 213 | software that is licensed under the GPLv2 ("Combined Software") and if a 214 | court of competent jurisdiction determines that the patent provision (Section 215 | 3), the indemnity provision (Section 9) or other Section of the License 216 | conflicts with the conditions of the GPLv2, you may retroactively and 217 | prospectively choose to deem waived or otherwise exclude such Section(s) of 218 | the License, but only in their entirety and only with respect to the Combined 219 | Software. 220 | 221 | -------------------------------------------------------------------------------- /lib/llvm/src/translate.rs: -------------------------------------------------------------------------------- 1 | //! Translation from LLVM IR to Cranelift IL. 2 | 3 | use cranelift_codegen; 4 | use cranelift_codegen::binemit::{NullTrapSink, NullStackmapSink}; 5 | use cranelift_codegen::ir; 6 | use cranelift_codegen::isa::TargetIsa; 7 | use cranelift_frontend; 8 | use libc; 9 | use llvm_sys::core::*; 10 | use llvm_sys::ir_reader::*; 11 | use llvm_sys::prelude::*; 12 | use llvm_sys::target::*; 13 | use llvm_sys::LLVMValueKind::*; 14 | use std::collections::hash_map; 15 | use std::error::Error; 16 | use std::ffi; 17 | use std::ptr; 18 | use std::str; 19 | use string_table::StringTable; 20 | 21 | use context::{Context, EbbInfo}; 22 | use module::{Compilation, CompiledFunction, DataSymbol, Module, SymbolKind}; 23 | use operations::{translate_function_params, translate_inst}; 24 | use reloc_sink::RelocSink; 25 | use types::translate_sig; 26 | 27 | /// Translate from an llvm-sys C-style string to a Rust String. 28 | pub fn translate_string(charstar: *const libc::c_char) -> Result { 29 | Ok(unsafe { ffi::CStr::from_ptr(charstar) } 30 | .to_str() 31 | .map_err(|err| err.description().to_string())? 32 | .to_string()) 33 | } 34 | 35 | /// Translate from an llvm-sys C-style string to an `ir::FunctionName`. 36 | pub fn translate_symbol_name( 37 | charstar: *const libc::c_char, 38 | strings: &StringTable, 39 | ) -> Result { 40 | Ok(strings.get_extname(translate_string(charstar)?)) 41 | } 42 | 43 | /// Create an LLVM Context. 44 | pub fn create_llvm_context() -> LLVMContextRef { 45 | unsafe { LLVMContextCreate() } 46 | } 47 | 48 | /// Read LLVM IR (bitcode or text) from a file and return the resulting module. 49 | pub fn read_llvm(llvm_ctx: LLVMContextRef, path: &str) -> Result { 50 | let mut msg = ptr::null_mut(); 51 | let mut buf = ptr::null_mut(); 52 | let c_str = ffi::CString::new(path).map_err(|err| err.description().to_string())?; 53 | let llvm_name = c_str.as_ptr(); 54 | if unsafe { LLVMCreateMemoryBufferWithContentsOfFile(llvm_name, &mut buf, &mut msg) } != 0 { 55 | return Err(format!( 56 | "error creating LLVM memory buffer for {}: {}", 57 | path, 58 | translate_string(msg)? 59 | )); 60 | } 61 | let mut module = ptr::null_mut(); 62 | if unsafe { LLVMParseIRInContext(llvm_ctx, buf, &mut module, &mut msg) } != 0 { 63 | Err(format!( 64 | "error parsing LLVM IR in {}: {}", 65 | path, 66 | translate_string(msg)? 67 | )) 68 | } else { 69 | Ok(module) 70 | } 71 | } 72 | 73 | /// Translate an LLVM module into Cranelift IL. 74 | pub fn translate_module( 75 | llvm_mod: LLVMModuleRef, 76 | isa: Option<&TargetIsa>, 77 | ) -> Result { 78 | // TODO: Use a more sophisticated API rather than just stuffing all 79 | // the functions into a Vec. 80 | let mut result = Module::new(); 81 | let dl = unsafe { LLVMGetModuleDataLayout(llvm_mod) }; 82 | 83 | // Declare all names. 84 | let mut llvm_func = unsafe { LLVMGetFirstFunction(llvm_mod) }; 85 | while !llvm_func.is_null() { 86 | let llvm_name = unsafe { LLVMGetValueName(llvm_func) }; 87 | result.strings.declare_extname(translate_string(llvm_name)?); 88 | llvm_func = unsafe { LLVMGetNextFunction(llvm_func) }; 89 | } 90 | let mut llvm_global = unsafe { LLVMGetFirstGlobal(llvm_mod) }; 91 | while !llvm_global.is_null() { 92 | let llvm_name = unsafe { LLVMGetValueName(llvm_global) }; 93 | result.strings.declare_extname(translate_string(llvm_name)?); 94 | llvm_global = unsafe { LLVMGetNextGlobal(llvm_global) }; 95 | } 96 | 97 | // Translate the Functions. 98 | let mut llvm_func = unsafe { LLVMGetFirstFunction(llvm_mod) }; 99 | while !llvm_func.is_null() { 100 | if unsafe { LLVMIsDeclaration(llvm_func) } == 0 { 101 | let func = translate_function(llvm_func, dl, isa, &result.strings)?; 102 | 103 | // Collect externally referenced symbols for the module. 104 | for func_ref in func.il.dfg.ext_funcs.keys() { 105 | let name = &func.il.dfg.ext_funcs[func_ref].name; 106 | // If this function is defined inside the module, don't list it 107 | // as an import. 108 | let c_str = ffi::CString::new(result.strings.get_str(name)) 109 | .map_err(|err| err.description().to_string())?; 110 | let llvm_str = c_str.as_ptr(); 111 | let llvm_func = unsafe { LLVMGetNamedFunction(llvm_mod, llvm_str) }; 112 | if llvm_func.is_null() || unsafe { LLVMIsDeclaration(llvm_func) } != 0 { 113 | result.imports.push((name.clone(), SymbolKind::Function)); 114 | } 115 | } 116 | for global_var in func.il.global_values.keys() { 117 | // TODO: Use the colocated field. 118 | if let ir::GlobalValueData::Symbol { 119 | ref name, 120 | offset: _offset, 121 | colocated: _colocated, 122 | } = func.il.global_values[global_var] 123 | { 124 | // If this global is defined inside the module, don't list it 125 | // as an import. 126 | let c_str = ffi::CString::new(result.strings.get_str(name)) 127 | .map_err(|err| err.description().to_string())?; 128 | let llvm_str = c_str.as_ptr(); 129 | let llvm_global = unsafe { LLVMGetNamedGlobal(llvm_mod, llvm_str) }; 130 | if llvm_global.is_null() || unsafe { LLVMIsDeclaration(llvm_global) } != 0 { 131 | result.imports.push((name.clone(), SymbolKind::Data)); 132 | } 133 | } 134 | } 135 | 136 | result.functions.push(func); 137 | } 138 | llvm_func = unsafe { LLVMGetNextFunction(llvm_func) }; 139 | } 140 | 141 | // Translate the GlobalVariables. 142 | let mut llvm_global = unsafe { LLVMGetFirstGlobal(llvm_mod) }; 143 | while !llvm_global.is_null() { 144 | if unsafe { LLVMIsThreadLocal(llvm_global) } != 0 { 145 | panic!("unimplemented: thread-local variables"); 146 | } 147 | if unsafe { LLVMIsDeclaration(llvm_global) } == 0 { 148 | let (name, contents) = translate_global(llvm_global, dl, &result.strings)?; 149 | result.data_symbols.push(DataSymbol { name, contents }); 150 | } 151 | llvm_global = unsafe { LLVMGetNextGlobal(llvm_global) }; 152 | } 153 | 154 | // TODO: GlobalAliases, ifuncs, metadata, comdat groups, inline asm 155 | 156 | Ok(result) 157 | } 158 | 159 | /// Translate the GlobalVariable `llvm_global` to Cranelift IL. 160 | pub fn translate_global( 161 | llvm_global: LLVMValueRef, 162 | dl: LLVMTargetDataRef, 163 | strings: &StringTable, 164 | ) -> Result<(ir::ExternalName, Vec), String> { 165 | let llvm_name = unsafe { LLVMGetValueName(llvm_global) }; 166 | let name = translate_symbol_name(llvm_name, strings)?; 167 | 168 | let llvm_ty = unsafe { LLVMGetElementType(LLVMTypeOf(llvm_global)) }; 169 | let size = unsafe { LLVMABISizeOfType(dl, llvm_ty) }; 170 | 171 | let llvm_init = unsafe { LLVMGetInitializer(llvm_global) }; 172 | let llvm_kind = unsafe { LLVMGetValueKind(llvm_init) }; 173 | let mut contents = Vec::new(); 174 | match llvm_kind { 175 | LLVMConstantIntValueKind => { 176 | let raw = unsafe { LLVMConstIntGetSExtValue(llvm_init) }; 177 | let mut part = raw; 178 | for _ in 0..size { 179 | contents.push((part & 0xff) as u8); 180 | part >>= 8; 181 | } 182 | } 183 | LLVMConstantAggregateZeroValueKind => { 184 | for _ in 0..size { 185 | contents.push(0u8); 186 | } 187 | } 188 | _ => panic!( 189 | "unimplemented constant initializer value kind: {:?}", 190 | llvm_kind 191 | ), 192 | } 193 | 194 | Ok((name, contents)) 195 | } 196 | 197 | /// Translate the Function `llvm_func` to Cranelift IL. 198 | pub fn translate_function( 199 | llvm_func: LLVMValueRef, 200 | dl: LLVMTargetDataRef, 201 | isa: Option<&TargetIsa>, 202 | strings: &StringTable, 203 | ) -> Result { 204 | // TODO: Reuse the context between separate invocations. 205 | let mut clif_ctx = cranelift_codegen::Context::new(); 206 | let llvm_name = unsafe { LLVMGetValueName(llvm_func) }; 207 | clif_ctx.func.name = translate_symbol_name(llvm_name, strings)?; 208 | clif_ctx.func.signature = 209 | translate_sig(unsafe { LLVMGetElementType(LLVMTypeOf(llvm_func)) }, dl); 210 | 211 | { 212 | let mut il_builder = cranelift_frontend::FunctionBuilderContext::new(); 213 | let mut ctx = Context::new(&mut clif_ctx.func, &mut il_builder, dl); 214 | 215 | // Make a pre-pass through the basic blocks to collect predecessor 216 | // information, which LLVM's C API doesn't expose directly. 217 | let mut llvm_bb = unsafe { LLVMGetFirstBasicBlock(llvm_func) }; 218 | while !llvm_bb.is_null() { 219 | prepare_for_bb(llvm_bb, &mut ctx); 220 | llvm_bb = unsafe { LLVMGetNextBasicBlock(llvm_bb) }; 221 | } 222 | 223 | // Translate the contents of each basic block. 224 | llvm_bb = unsafe { LLVMGetFirstBasicBlock(llvm_func) }; 225 | while !llvm_bb.is_null() { 226 | translate_bb(llvm_func, llvm_bb, &mut ctx, strings); 227 | llvm_bb = unsafe { LLVMGetNextBasicBlock(llvm_bb) }; 228 | } 229 | } 230 | 231 | if let Some(isa) = isa { 232 | let code_size = clif_ctx.compile(isa).map_err(|err| err.to_string())?.code_size; 233 | let mut code_buf: Vec = Vec::with_capacity(code_size as usize); 234 | let mut reloc_sink = RelocSink::new(); 235 | let mut trap_sink = NullTrapSink {}; 236 | let mut stackmap_sink = NullStackmapSink {}; 237 | code_buf.resize(code_size as usize, 0); 238 | // TODO: Use the safe interface instead. 239 | unsafe { 240 | clif_ctx.emit_to_memory(isa, code_buf.as_mut_ptr(), &mut reloc_sink, &mut trap_sink, &mut stackmap_sink); 241 | } 242 | 243 | Ok(CompiledFunction { 244 | il: clif_ctx.func, 245 | compilation: Some(Compilation { 246 | body: code_buf, 247 | relocs: reloc_sink, 248 | }), 249 | }) 250 | } else { 251 | Ok(CompiledFunction { 252 | il: clif_ctx.func, 253 | compilation: None, 254 | }) 255 | } 256 | } 257 | 258 | /// Since LLVM's C API doesn't expose predecessor accessors, we make a prepass 259 | /// and collect the information we need from the successor accessors. 260 | fn prepare_for_bb(llvm_bb: LLVMBasicBlockRef, ctx: &mut Context) { 261 | let term = unsafe { LLVMGetBasicBlockTerminator(llvm_bb) }; 262 | let is_switch = !unsafe { LLVMIsASwitchInst(term) }.is_null(); 263 | let num_succs = unsafe { LLVMGetNumSuccessors(term) }; 264 | for i in 0..num_succs { 265 | let llvm_succ = unsafe { LLVMGetSuccessor(term, i) }; 266 | { 267 | let info = ctx.ebb_info 268 | .entry(llvm_succ) 269 | .or_insert_with(EbbInfo::default); 270 | info.num_preds_left += 1; 271 | } 272 | // If the block is reachable by branch (and not fallthrough), or by 273 | // a switch non-default edge (which can't use fallthrough), we need 274 | // an Ebb entry for it. 275 | if (is_switch && i != 0) || llvm_succ != unsafe { LLVMGetNextBasicBlock(llvm_bb) } { 276 | ctx.ebb_map.insert(llvm_succ, ctx.builder.create_ebb()); 277 | } 278 | } 279 | } 280 | 281 | /// Translate the contents of `llvm_bb` to Cranelift IL instructions. 282 | fn translate_bb( 283 | llvm_func: LLVMValueRef, 284 | llvm_bb: LLVMBasicBlockRef, 285 | ctx: &mut Context, 286 | strings: &StringTable, 287 | ) { 288 | // Set up the Ebb as needed. 289 | if ctx.ebb_info.get(&llvm_bb).is_none() { 290 | // Block has no predecessors. 291 | let entry_block = llvm_bb == unsafe { LLVMGetEntryBasicBlock(llvm_func) }; 292 | let ebb = ctx.builder.create_ebb(); 293 | ctx.builder.seal_block(ebb); 294 | ctx.builder.switch_to_block(ebb); 295 | if entry_block { 296 | // It's the entry block. Add the parameters. 297 | translate_function_params(llvm_func, ebb, ctx); 298 | } 299 | } else if let hash_map::Entry::Occupied(entry) = ctx.ebb_map.entry(llvm_bb) { 300 | // Block has predecessors and is branched to, so it starts a new Ebb. 301 | let ebb = *entry.get(); 302 | ctx.builder.switch_to_block(ebb); 303 | } 304 | 305 | // Translate each regular instruction. 306 | let mut llvm_inst = unsafe { LLVMGetFirstInstruction(llvm_bb) }; 307 | while !llvm_inst.is_null() { 308 | translate_inst(llvm_bb, llvm_inst, ctx, strings); 309 | llvm_inst = unsafe { LLVMGetNextInstruction(llvm_inst) }; 310 | } 311 | 312 | // Visit each CFG successor and seal blocks that have had all their 313 | // predecessors visited. 314 | let term = unsafe { LLVMGetBasicBlockTerminator(llvm_bb) }; 315 | let num_succs = unsafe { LLVMGetNumSuccessors(term) }; 316 | for i in 0..num_succs { 317 | let llvm_succ = unsafe { LLVMGetSuccessor(term, i) }; 318 | let info = ctx.ebb_info.get_mut(&llvm_succ).unwrap(); 319 | debug_assert!(info.num_preds_left > 0); 320 | info.num_preds_left -= 1; 321 | if info.num_preds_left == 0 { 322 | if let Some(ebb) = ctx.ebb_map.get(&llvm_succ) { 323 | ctx.builder.seal_block(*ebb); 324 | } 325 | } 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /lib/llvm/src/operations.rs: -------------------------------------------------------------------------------- 1 | //! Translation from LLVM IR operations to Cranelift IL instructions. 2 | 3 | use cranelift_codegen::ir::{self, Ebb, InstBuilder}; 4 | use cranelift_codegen::isa::CallConv; 5 | 6 | use libc; 7 | use llvm_sys::core::*; 8 | use llvm_sys::prelude::*; 9 | use llvm_sys::target::*; 10 | use llvm_sys::LLVMAtomicOrdering::*; 11 | use llvm_sys::LLVMCallConv::*; 12 | use llvm_sys::LLVMIntPredicate::*; 13 | use llvm_sys::LLVMOpcode::*; 14 | use llvm_sys::LLVMRealPredicate::*; 15 | use llvm_sys::LLVMTypeKind::*; 16 | use llvm_sys::LLVMValueKind::*; 17 | use llvm_sys::*; 18 | use std::collections::hash_map; 19 | use std::mem; 20 | use std::ptr; 21 | use string_table::StringTable; 22 | 23 | use context::Context; 24 | use translate::{translate_string, translate_symbol_name}; 25 | use types::{translate_pointer_type, translate_sig, translate_type}; 26 | use cranelift_codegen::entity::EntityRef; 27 | use cranelift_frontend::Variable; 28 | 29 | /// Translate the incoming parameters for `llvm_func` into Cranelift values 30 | /// defined in the entry block. 31 | pub fn translate_function_params(llvm_func: LLVMValueRef, entry_ebb: Ebb, ctx: &mut Context) { 32 | ctx.builder.append_ebb_params_for_function_params(entry_ebb); 33 | for i in 0..unsafe { LLVMCountParams(llvm_func) } { 34 | let llvm_param = unsafe { LLVMGetParam(llvm_func, i) }; 35 | let val = ctx.builder.ebb_params(entry_ebb)[i as usize]; 36 | def_val(llvm_param, val, ctx); 37 | } 38 | } 39 | 40 | /// Translate `llvm_inst`, which is a normal instruction, to Cranelift IL 41 | /// instructions. 42 | pub fn translate_inst( 43 | llvm_bb: LLVMBasicBlockRef, 44 | llvm_inst: LLVMValueRef, 45 | ctx: &mut Context, 46 | strings: &StringTable, 47 | ) { 48 | let llvm_opcode = unsafe { LLVMGetInstructionOpcode(llvm_inst) }; 49 | if let Some(result) = translate_operation(llvm_bb, llvm_opcode, llvm_inst, ctx, strings) { 50 | def_val(llvm_inst, result, ctx); 51 | } 52 | } 53 | 54 | /// Translate `llvm_val`, which is either an `Instruction` or a `ConstantExpr`, 55 | /// with `llvm_opcode` as the opcode. 56 | fn translate_operation( 57 | llvm_bb: LLVMBasicBlockRef, 58 | llvm_opcode: LLVMOpcode, 59 | llvm_val: LLVMValueRef, 60 | ctx: &mut Context, 61 | strings: &StringTable, 62 | ) -> Option { 63 | Some(match llvm_opcode { 64 | LLVMPHI => { 65 | // Nothing to do. Phis are handled elsewhere. 66 | return None; 67 | } 68 | LLVMAdd => match binary_operands_r_ri(llvm_val, ctx, strings) { 69 | RegImmOperands::Bool(lhs, rhs) => ctx.builder.ins().bxor(lhs, rhs), 70 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().iadd(lhs, rhs), 71 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().iadd_imm(lhs, rhs), 72 | }, 73 | LLVMSub => { 74 | // TODO: use irsub_imm when applicable. 75 | match binary_operands_r_ri(llvm_val, ctx, strings) { 76 | RegImmOperands::Bool(lhs, rhs) => ctx.builder.ins().bxor_not(lhs, rhs), 77 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().isub(lhs, rhs), 78 | RegImmOperands::RegImm(lhs, rhs) => { 79 | // Cranelift has no isub_imm; it uses iadd_imm with a 80 | // negated immediate instead. 81 | let raw_rhs: i64 = rhs.into(); 82 | ctx.builder 83 | .ins() 84 | .iadd_imm(lhs, ir::immediates::Imm64::from(raw_rhs.wrapping_neg())) 85 | } 86 | } 87 | } 88 | LLVMMul => match binary_operands_r_ri(llvm_val, ctx, strings) { 89 | RegImmOperands::Bool(lhs, rhs) => ctx.builder.ins().band(lhs, rhs), 90 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().imul(lhs, rhs), 91 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().imul_imm(lhs, rhs), 92 | }, 93 | LLVMSDiv => match binary_operands_r_ri(llvm_val, ctx, strings) { 94 | RegImmOperands::Bool(lhs, _rhs) => lhs, 95 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().sdiv(lhs, rhs), 96 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().sdiv_imm(lhs, rhs), 97 | }, 98 | LLVMUDiv => match binary_operands_r_ri(llvm_val, ctx, strings) { 99 | RegImmOperands::Bool(lhs, _rhs) => lhs, 100 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().udiv(lhs, rhs), 101 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().udiv_imm(lhs, rhs), 102 | }, 103 | LLVMSRem => match binary_operands_r_ri(llvm_val, ctx, strings) { 104 | RegImmOperands::Bool(_lhs, _rhs) => { 105 | let ty = translate_type_of(llvm_val, ctx.dl); 106 | ctx.builder.ins().bconst(ty, false) 107 | } 108 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().srem(lhs, rhs), 109 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().srem_imm(lhs, rhs), 110 | }, 111 | LLVMURem => match binary_operands_r_ri(llvm_val, ctx, strings) { 112 | RegImmOperands::Bool(_lhs, _rhs) => { 113 | let ty = translate_type_of(llvm_val, ctx.dl); 114 | ctx.builder.ins().bconst(ty, false) 115 | } 116 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().urem(lhs, rhs), 117 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().urem_imm(lhs, rhs), 118 | }, 119 | LLVMAShr => match binary_operands_r_ri(llvm_val, ctx, strings) { 120 | RegImmOperands::Bool(lhs, _rhs) => lhs, 121 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().sshr(lhs, rhs), 122 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().sshr_imm(lhs, rhs), 123 | }, 124 | LLVMLShr => match binary_operands_r_ri(llvm_val, ctx, strings) { 125 | RegImmOperands::Bool(lhs, _rhs) => lhs, 126 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().ushr(lhs, rhs), 127 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().ushr_imm(lhs, rhs), 128 | }, 129 | LLVMShl => match binary_operands_r_ri(llvm_val, ctx, strings) { 130 | RegImmOperands::Bool(lhs, _rhs) => lhs, 131 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().ishl(lhs, rhs), 132 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().ishl_imm(lhs, rhs), 133 | }, 134 | LLVMAnd => match binary_operands_r_ri(llvm_val, ctx, strings) { 135 | RegImmOperands::Bool(lhs, rhs) | RegImmOperands::RegReg(lhs, rhs) => { 136 | ctx.builder.ins().band(lhs, rhs) 137 | } 138 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().band_imm(lhs, rhs), 139 | }, 140 | LLVMOr => match binary_operands_r_ri(llvm_val, ctx, strings) { 141 | RegImmOperands::Bool(lhs, rhs) | RegImmOperands::RegReg(lhs, rhs) => { 142 | ctx.builder.ins().bor(lhs, rhs) 143 | } 144 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().bor_imm(lhs, rhs), 145 | }, 146 | LLVMXor => match binary_operands_r_ri(llvm_val, ctx, strings) { 147 | RegImmOperands::Bool(lhs, rhs) | RegImmOperands::RegReg(lhs, rhs) => { 148 | ctx.builder.ins().bxor(lhs, rhs) 149 | } 150 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().bxor_imm(lhs, rhs), 151 | }, 152 | LLVMFAdd => { 153 | let (lhs, rhs) = binary_operands(llvm_val, ctx, strings); 154 | ctx.builder.ins().fadd(lhs, rhs) 155 | } 156 | LLVMFSub => { 157 | let (lhs, rhs) = binary_operands(llvm_val, ctx, strings); 158 | ctx.builder.ins().fsub(lhs, rhs) 159 | } 160 | LLVMFMul => { 161 | let (lhs, rhs) = binary_operands(llvm_val, ctx, strings); 162 | ctx.builder.ins().fmul(lhs, rhs) 163 | } 164 | LLVMFDiv => { 165 | let (lhs, rhs) = binary_operands(llvm_val, ctx, strings); 166 | ctx.builder.ins().fdiv(lhs, rhs) 167 | } 168 | LLVMFRem => { 169 | let (lhs, rhs) = binary_operands(llvm_val, ctx, strings); 170 | let ty = translate_type_of(llvm_val, ctx.dl); 171 | // TODO: Pick up the default target calling convention. 172 | let mut sig = ir::Signature::new(CallConv::SystemV); 173 | sig.params.resize(2, ir::AbiParam::new(ty)); 174 | sig.returns.push(ir::AbiParam::new(ty)); 175 | let data = ir::ExtFuncData { 176 | name: strings.get_extname(match ty { 177 | ir::types::F32 => "fmodf", 178 | ir::types::F64 => "fmod", 179 | _ => panic!("frem unimplemented for type {:?}", ty), 180 | }), 181 | signature: ctx.builder.import_signature(sig), 182 | colocated: false, // TODO: Set this flag 183 | }; 184 | let callee = ctx.builder.import_function(data); 185 | let call = ctx.builder.ins().call(callee, &[lhs, rhs]); 186 | ctx.builder.inst_results(call)[0] 187 | } 188 | LLVMICmp => { 189 | let llvm_condcode = unsafe { LLVMGetICmpPredicate(llvm_val) }; 190 | let condcode = translate_icmp_code(llvm_condcode); 191 | match binary_operands_r_ri(llvm_val, ctx, strings) { 192 | RegImmOperands::Bool(lhs, rhs) => translate_bool_cmp(condcode, lhs, rhs, ctx), 193 | RegImmOperands::RegReg(lhs, rhs) => ctx.builder.ins().icmp(condcode, lhs, rhs), 194 | RegImmOperands::RegImm(lhs, rhs) => ctx.builder.ins().icmp_imm(condcode, lhs, rhs), 195 | } 196 | } 197 | LLVMFCmp => { 198 | let (lhs, rhs) = binary_operands(llvm_val, ctx, strings); 199 | let condcode = unsafe { LLVMGetFCmpPredicate(llvm_val) }; 200 | match condcode { 201 | LLVMRealPredicateFalse => ctx.builder.ins().bconst(ir::types::B1, false), 202 | LLVMRealPredicateTrue => ctx.builder.ins().bconst(ir::types::B1, true), 203 | _ => ctx.builder 204 | .ins() 205 | .fcmp(translate_fcmp_code(condcode), lhs, rhs), 206 | } 207 | } 208 | LLVMTrunc | LLVMZExt => { 209 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 210 | let op = use_val(llvm_op, ctx, strings); 211 | let from = translate_type_of(llvm_op, ctx.dl); 212 | let to = translate_type_of(llvm_val, ctx.dl); 213 | unsigned_cast(from, to, op, ctx) 214 | } 215 | LLVMSExt => { 216 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 217 | let op = use_val(llvm_op, ctx, strings); 218 | let from = translate_type_of(llvm_op, ctx.dl); 219 | let to = translate_type_of(llvm_val, ctx.dl); 220 | if from.is_bool() { 221 | ctx.builder.ins().bmask(to, op) 222 | } else { 223 | ctx.builder.ins().sextend(to, op) 224 | } 225 | } 226 | LLVMFPToSI => { 227 | let op = unary_operands(llvm_val, ctx, strings); 228 | let ty = translate_type_of(llvm_val, ctx.dl); 229 | if ty.is_bool() { 230 | let sint = ctx.builder.ins().fcvt_to_sint(ir::types::I32, op); 231 | ctx.builder 232 | .ins() 233 | .icmp_imm(ir::condcodes::IntCC::NotEqual, sint, 0) 234 | } else { 235 | ctx.builder.ins().fcvt_to_sint(ty, op) 236 | } 237 | } 238 | LLVMFPToUI => { 239 | let op = unary_operands(llvm_val, ctx, strings); 240 | let ty = translate_type_of(llvm_val, ctx.dl); 241 | if ty.is_bool() { 242 | let uint = ctx.builder.ins().fcvt_to_uint(ir::types::I32, op); 243 | ctx.builder 244 | .ins() 245 | .icmp_imm(ir::condcodes::IntCC::NotEqual, uint, 0) 246 | } else { 247 | ctx.builder.ins().fcvt_to_uint(ty, op) 248 | } 249 | } 250 | LLVMSIToFP => { 251 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 252 | let op = use_val(llvm_op, ctx, strings); 253 | let from = translate_type_of(llvm_op, ctx.dl); 254 | let to = translate_type_of(llvm_val, ctx.dl); 255 | if from.is_bool() { 256 | let sint = ctx.builder.ins().bmask(ir::types::I32, op); 257 | ctx.builder.ins().fcvt_from_sint(to, sint) 258 | } else { 259 | ctx.builder.ins().fcvt_from_sint(to, op) 260 | } 261 | } 262 | LLVMUIToFP => { 263 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 264 | let op = use_val(llvm_op, ctx, strings); 265 | let from = translate_type_of(llvm_op, ctx.dl); 266 | let to = translate_type_of(llvm_val, ctx.dl); 267 | if from.is_bool() { 268 | let uint = ctx.builder.ins().bint(ir::types::I32, op); 269 | ctx.builder.ins().fcvt_from_uint(to, uint) 270 | } else { 271 | ctx.builder.ins().fcvt_from_uint(to, op) 272 | } 273 | } 274 | LLVMFPTrunc => { 275 | let op = unary_operands(llvm_val, ctx, strings); 276 | let ty = translate_type_of(llvm_val, ctx.dl); 277 | ctx.builder.ins().fdemote(ty, op) 278 | } 279 | LLVMFPExt => { 280 | let op = unary_operands(llvm_val, ctx, strings); 281 | let ty = translate_type_of(llvm_val, ctx.dl); 282 | ctx.builder.ins().fpromote(ty, op) 283 | } 284 | LLVMBitCast => { 285 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 286 | let op = use_val(llvm_op, ctx, strings); 287 | let from = translate_type_of(llvm_op, ctx.dl); 288 | let to = translate_type_of(llvm_val, ctx.dl); 289 | if from == to { 290 | // No-op bitcast. 291 | op 292 | } else { 293 | ctx.builder.ins().bitcast(to, op) 294 | } 295 | } 296 | LLVMPtrToInt | LLVMIntToPtr => { 297 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 298 | let op = use_val(llvm_op, ctx, strings); 299 | let from = translate_type_of(llvm_op, ctx.dl); 300 | let to = translate_type_of(llvm_val, ctx.dl); 301 | unsigned_cast(from, to, op, ctx) 302 | } 303 | LLVMSelect => { 304 | let (c, t, f) = ternary_operands(llvm_val, ctx, strings); 305 | ctx.builder.ins().select(c, t, f) 306 | } 307 | LLVMLoad => { 308 | let llvm_ty = unsafe { LLVMTypeOf(llvm_val) }; 309 | let flags = translate_memflags(llvm_val, llvm_ty, ctx); 310 | let op = unary_operands(llvm_val, ctx, strings); 311 | let ty = translate_type(llvm_ty, ctx.dl); 312 | if ty.is_bool() { 313 | let load = ctx.builder.ins().load(ir::types::I8, flags, op, 0); 314 | unsigned_cast(ir::types::I8, ty, load, ctx) 315 | } else { 316 | ctx.builder.ins().load(ty, flags, op, 0) 317 | } 318 | } 319 | LLVMStore => { 320 | let llvm_ty = unsafe { LLVMTypeOf(LLVMGetOperand(llvm_val, 0)) }; 321 | let flags = translate_memflags(llvm_val, llvm_ty, ctx); 322 | let (val, ptr) = binary_operands(llvm_val, ctx, strings); 323 | let ty = translate_type(llvm_ty, ctx.dl); 324 | let store_val = if ty.is_bool() { 325 | unsigned_cast(ty, ir::types::I8, val, ctx) 326 | } else { 327 | val 328 | }; 329 | ctx.builder.ins().store(flags, store_val, ptr, 0); 330 | return None; 331 | } 332 | LLVMBr => { 333 | if unsafe { LLVMIsConditional(llvm_val) } != 0 { 334 | let cond = unary_operands(llvm_val, ctx, strings); 335 | let llvm_true_succ = successor(llvm_val, 0); 336 | let llvm_false_succ = successor(llvm_val, 1); 337 | let llvm_next_bb = unsafe { LLVMGetNextBasicBlock(llvm_bb) }; 338 | // A conditional branch in Cranelift always falls through in 339 | // the not-taken case, so test whether either successor of 340 | // the LLVM IR conditional branch can be a fallthrough. If not, 341 | // an unconditional branch can be added. 342 | if llvm_next_bb == llvm_true_succ { 343 | // It's valid for both destinations to be fallthroughs. 344 | if llvm_next_bb != llvm_false_succ { 345 | handle_phi_operands(llvm_bb, llvm_false_succ, ctx, strings); 346 | ctx.builder 347 | .ins() 348 | .brz(cond, ctx.ebb_map[&llvm_false_succ], &[]); 349 | } 350 | jump(llvm_bb, llvm_true_succ, ctx, strings); 351 | } else { 352 | handle_phi_operands(llvm_bb, llvm_true_succ, ctx, strings); 353 | ctx.builder 354 | .ins() 355 | .brnz(cond, ctx.ebb_map[&llvm_true_succ], &[]); 356 | jump(llvm_bb, llvm_false_succ, ctx, strings); 357 | } 358 | } else { 359 | let llvm_succ = successor(llvm_val, 0); 360 | jump(llvm_bb, llvm_succ, ctx, strings); 361 | } 362 | return None; 363 | } 364 | LLVMSwitch => { 365 | // TODO: We'd really want getNumCases or ConstCaseIt here, but 366 | // LLVM's C API doesn't expose those currently. 367 | let num_cases = unsafe { LLVMGetNumOperands(llvm_val) / 2 - 1 }; 368 | let mut data = ir::JumpTableData::with_capacity(num_cases as usize); 369 | for i in 0..num_cases { 370 | let llvm_key = unsafe { LLVMGetOperand(llvm_val, (i as libc::c_uint + 1) * 2) }; 371 | if unsafe { LLVMConstIntGetZExtValue(llvm_key) } != i as u64 { 372 | panic!("unimplemented: switches with non-sequential cases"); 373 | } 374 | let llvm_case = unsafe { LLVMGetSuccessor(llvm_val, (i + 1) as libc::c_uint) }; 375 | data.push_entry(ctx.ebb_map[&llvm_case]); 376 | } 377 | let jt = ctx.builder.create_jump_table(data); 378 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 379 | let op = use_val(llvm_op, ctx, strings); 380 | let op_ty = translate_type_of(llvm_op, ctx.dl); 381 | let index = if op_ty.is_bool() { 382 | unsigned_cast(op_ty, ir::types::I8, op, ctx) 383 | } else { 384 | op 385 | }; 386 | let llvm_default = unsafe { LLVMGetSwitchDefaultDest(llvm_val) }; 387 | ctx.builder.ins().br_table(index, ctx.ebb_map[&llvm_default], jt); 388 | jump(llvm_bb, llvm_default, ctx, strings); 389 | return None; 390 | } 391 | LLVMAlloca => { 392 | let llvm_op = unsafe { LLVMGetOperand(llvm_val, 0) }; 393 | let align = unsafe { LLVMGetAlignment(llvm_val) }; 394 | let llvm_allocty = unsafe { LLVMGetAllocatedType(llvm_val) }; 395 | // TODO: We'd really want isArrayAllocation and isStaticAlloca here, but 396 | // LLVM's C API doesn't expose those currently. 397 | if unsafe { LLVMIsConstant(llvm_op) } == 0 { 398 | panic!("unimplemented: dynamic alloca"); 399 | } 400 | if llvm_bb != unsafe { LLVMGetEntryBasicBlock(LLVMGetBasicBlockParent(llvm_bb)) } { 401 | panic!("unimplemented: alloca outside of entry block"); 402 | } 403 | if unsafe { LLVMGetValueKind(llvm_op) } != LLVMConstantIntValueKind { 404 | panic!("unimplemented: ConstantExpr alloca size"); 405 | } 406 | if align > unsafe { LLVMABIAlignmentOfType(ctx.dl, llvm_allocty) } { 407 | panic!("unimplemented: supernaturally aligned alloca"); 408 | } 409 | let size = unsafe { LLVMConstIntGetZExtValue(llvm_op) } 410 | * unsafe { LLVMABISizeOfType(ctx.dl, llvm_allocty) }; 411 | if u64::from(size as u32) != size { 412 | panic!("unimplemented: alloca size computation doesn't fit in u32"); 413 | } 414 | let stack_slot_data = 415 | ir::StackSlotData::new(ir::StackSlotKind::ExplicitSlot, size as u32); 416 | let stack_slot = ctx.builder.create_stack_slot(stack_slot_data); 417 | let pointer_type = translate_pointer_type(ctx.dl); 418 | ctx.builder.ins().stack_addr(pointer_type, stack_slot, 0) 419 | } 420 | LLVMGetElementPtr => { 421 | let pointer_type = translate_pointer_type(ctx.dl); 422 | let llvm_ptr = unsafe { LLVMGetOperand(llvm_val, 0) }; 423 | let mut llvm_gepty = unsafe { LLVMTypeOf(llvm_ptr) }; 424 | let mut ptr = use_val(llvm_ptr, ctx, strings); 425 | let mut imm = 0; 426 | for i in 1..unsafe { LLVMGetNumOperands(llvm_val) } as libc::c_uint { 427 | let index = unsafe { LLVMGetOperand(llvm_val, i) }; 428 | let (new_llvm_gepty, new_ptr, new_imm) = 429 | translate_gep_index(llvm_gepty, ptr, imm, pointer_type, index, ctx, strings); 430 | llvm_gepty = new_llvm_gepty; 431 | ptr = new_ptr; 432 | imm = new_imm; 433 | } 434 | if imm != 0 { 435 | ptr = ctx.builder.ins().iadd_imm(ptr, imm); 436 | } 437 | ptr 438 | } 439 | LLVMCall => { 440 | let num_args = unsafe { LLVMGetNumArgOperands(llvm_val) } as usize; 441 | let callee_index = unsafe { LLVMGetNumOperands(llvm_val) } - 1; 442 | let llvm_callee = unsafe { LLVMGetOperand(llvm_val, callee_index as libc::c_uint) }; 443 | 444 | if unsafe { LLVMGetIntrinsicID(llvm_callee) } != 0 { 445 | return translate_intrinsic(llvm_val, llvm_callee, ctx, strings); 446 | } 447 | 448 | let llvm_functy = unsafe { LLVMGetElementType(LLVMTypeOf(llvm_callee)) }; 449 | if unsafe { LLVMIsFunctionVarArg(llvm_functy) } != 0 450 | && unsafe { LLVMCountParamTypes(llvm_functy) } as usize != num_args 451 | { 452 | panic!("unimplemented: variadic arguments"); 453 | } 454 | 455 | // Fast and cold are not ABI-exposed, so we can handle them however 456 | // we like. Just handle them the same as normal calls for now. 457 | let callconv = unsafe { LLVMGetInstructionCallConv(llvm_val) }; 458 | if callconv != LLVMCCallConv as libc::c_uint 459 | && callconv != LLVMFastCallConv as libc::c_uint 460 | && callconv != LLVMColdCallConv as libc::c_uint 461 | { 462 | panic!("unimplemented calling convention: {}", callconv); 463 | } 464 | // Collect the call arguments. 465 | // TODO: Implement ABI-exposed argument attributes such as byval, 466 | // signext, zeroext, inreg, inalloca, align. 467 | let mut args = Vec::with_capacity(num_args); 468 | for i in 0..num_args { 469 | debug_assert_eq!(i as libc::c_uint as usize, i); 470 | args.push(use_val( 471 | unsafe { LLVMGetOperand(llvm_val, i as libc::c_uint) }, 472 | ctx, 473 | strings, 474 | )); 475 | } 476 | let signature = ctx.builder 477 | .import_signature(translate_sig(llvm_functy, ctx.dl)); 478 | let name = translate_symbol_name(unsafe { LLVMGetValueName(llvm_callee) }, strings) 479 | .expect("unimplemented: unusual function names"); 480 | let call = if unsafe { LLVMGetValueKind(llvm_callee) } == LLVMFunctionValueKind { 481 | let data = ir::ExtFuncData { 482 | name, 483 | signature, 484 | colocated: false, // TODO: Set this flag 485 | }; 486 | let callee = ctx.builder.import_function(data); 487 | ctx.builder.ins().call(callee, &args) 488 | } else { 489 | let callee = use_val(llvm_callee, ctx, strings); 490 | ctx.builder.ins().call_indirect(signature, callee, &args) 491 | }; 492 | if translate_type_of(llvm_val, ctx.dl) != ir::types::INVALID { 493 | let results = ctx.builder.inst_results(call); 494 | debug_assert_eq!(results.len(), 1); 495 | results[0] 496 | } else { 497 | return None; 498 | } 499 | } 500 | LLVMRet => { 501 | if unsafe { LLVMGetNumOperands(llvm_val) } == 0 { 502 | ctx.builder.ins().return_(&[]); 503 | } else { 504 | // TODO: multiple return values 505 | let op = unary_operands(llvm_val, ctx, strings); 506 | ctx.builder.ins().return_(&[op]); 507 | } 508 | return None; 509 | } 510 | LLVMUnreachable => { 511 | ctx.builder.ins().trap(ir::TrapCode::User(0)); 512 | return None; 513 | } 514 | _ => panic!("unimplemented opcode: {:?}", llvm_opcode), 515 | }) 516 | } 517 | 518 | /// Produce a Cranelift Value holding the value of an LLVM IR Constant. 519 | fn materialize_constant( 520 | llvm_val: LLVMValueRef, 521 | ctx: &mut Context, 522 | strings: &StringTable, 523 | ) -> ir::Value { 524 | let llvm_kind = unsafe { LLVMGetValueKind(llvm_val) }; 525 | match llvm_kind { 526 | LLVMUndefValueValueKind => { 527 | // Cranelift has no undef; emit a zero. 528 | let ty = translate_type_of(llvm_val, ctx.dl); 529 | if ty.is_int() { 530 | ctx.builder.ins().iconst(ty, 0) 531 | } else if ty.is_bool() { 532 | ctx.builder.ins().bconst(ty, false) 533 | } else if ty == ir::types::F32 { 534 | ctx.builder 535 | .ins() 536 | .f32const(ir::immediates::Ieee32::with_bits(0)) 537 | } else if ty == ir::types::F64 { 538 | ctx.builder 539 | .ins() 540 | .f64const(ir::immediates::Ieee64::with_bits(0)) 541 | } else { 542 | panic!("unimplemented undef type: {}", ty); 543 | } 544 | } 545 | LLVMConstantIntValueKind => { 546 | let ty = translate_type_of(llvm_val, ctx.dl); 547 | let raw = unsafe { LLVMConstIntGetSExtValue(llvm_val) }; 548 | if ty.is_int() { 549 | ctx.builder.ins().iconst(ty, raw) 550 | } else if ty.is_bool() { 551 | ctx.builder.ins().bconst(ty, raw != 0) 552 | } else { 553 | panic!("unexpected ConstantInt type"); 554 | } 555 | } 556 | LLVMConstantPointerNullValueKind => { 557 | let ty = translate_pointer_type(ctx.dl); 558 | ctx.builder.ins().iconst(ty, 0) 559 | } 560 | LLVMFunctionValueKind => { 561 | let signature = ctx.builder.import_signature(translate_sig( 562 | unsafe { LLVMGetElementType(LLVMTypeOf(llvm_val)) }, 563 | ctx.dl, 564 | )); 565 | let name = translate_symbol_name(unsafe { LLVMGetValueName(llvm_val) }, strings) 566 | .expect("unimplemented: unusual symbol names"); 567 | let callee = ctx.builder.import_function(ir::ExtFuncData { 568 | name, 569 | signature, 570 | colocated: false, // TODO: Set this flag 571 | }); 572 | let ty = translate_pointer_type(ctx.dl); 573 | ctx.builder.ins().func_addr(ty, callee) 574 | } 575 | LLVMGlobalAliasValueKind | LLVMGlobalVariableValueKind => { 576 | let name = translate_symbol_name(unsafe { LLVMGetValueName(llvm_val) }, strings) 577 | .expect("unimplemented: unusual symbol names"); 578 | let global = ctx.builder.create_global_value(ir::GlobalValueData::Symbol { 579 | name, 580 | offset: ir::immediates::Imm64::new(0), 581 | colocated: false, // TODO: Set this flag 582 | }); 583 | let ty = translate_pointer_type(ctx.dl); 584 | ctx.builder.ins().global_value(ty, global) 585 | } 586 | LLVMConstantFPValueKind => { 587 | let mut loses_info = [0]; 588 | let val = unsafe { LLVMConstRealGetDouble(llvm_val, loses_info.as_mut_ptr()) }; 589 | debug_assert_eq!( 590 | loses_info[0], 0, 591 | "unimplemented floating-point constant value" 592 | ); 593 | match translate_type_of(llvm_val, ctx.dl) { 594 | ir::types::F32 => { 595 | let f32val = val as f32; 596 | ctx.builder 597 | .ins() 598 | .f32const(ir::immediates::Ieee32::with_bits(unsafe { 599 | mem::transmute(f32val) 600 | })) 601 | } 602 | ir::types::F64 => ctx.builder 603 | .ins() 604 | .f64const(ir::immediates::Ieee64::with_bits(unsafe { 605 | mem::transmute(val) 606 | })), 607 | ty => panic!("unimplemented floating-point constant type: {}", ty), 608 | } 609 | } 610 | LLVMConstantExprValueKind => { 611 | let llvm_opcode = unsafe { LLVMGetConstOpcode(llvm_val) }; 612 | translate_operation(ptr::null_mut(), llvm_opcode, llvm_val, ctx, strings) 613 | .expect("Constants don't return void") 614 | } 615 | _ => panic!("unimplemented constant kind: {:?}", llvm_kind), 616 | } 617 | } 618 | 619 | /// Translate an LLVM IR intrinsic call to Cranelift. 620 | fn translate_intrinsic( 621 | llvm_inst: LLVMValueRef, 622 | llvm_callee: LLVMValueRef, 623 | ctx: &mut Context, 624 | strings: &StringTable, 625 | ) -> Option { 626 | // LLVM's C API doesn't expose intrinsic IDs yet, so we match by name. 627 | let name = translate_string(unsafe { LLVMGetValueName(llvm_callee) }) 628 | .expect("unimplemented: unusual function names"); 629 | Some(match name.as_ref() { 630 | "llvm.dbg.addr" 631 | | "llvm.dbg.declare" 632 | | "llvm.dbg.value" 633 | | "llvm.prefetch" 634 | | "llvm.assume" 635 | | "llvm.lifetime.start.p0i8" 636 | | "llvm.lifetime.end.p0i8" 637 | | "llvm.invariant.start.p0i8" 638 | | "llvm.invariant.end.p0i8" 639 | | "llvm.sideeffect" 640 | | "llvm.codeview.annotation" => { 641 | // For now, just discard this informtion. 642 | return None; 643 | } 644 | "llvm.ssa_copy.i1" 645 | | "llvm.ssa_copy.i8" 646 | | "llvm.ssa_copy.i16" 647 | | "llvm.ssa_copy.i32" 648 | | "llvm.ssa_copy.i64" 649 | | "llvm.ssa_copy.f32" 650 | | "llvm.ssa_copy.f64" 651 | | "llvm.annotation.i8" 652 | | "llvm.annotation.i16" 653 | | "llvm.annotation.i32" 654 | | "llvm.annotation.i64" 655 | | "llvm.invariant.group.barrier" 656 | | "llvm.expect.i1" 657 | | "llvm.expect.i8" 658 | | "llvm.expect.i16" 659 | | "llvm.expect.i32" 660 | | "llvm.expect.i64" => { 661 | // For now, just discard the extra informtion these intrinsics 662 | // provide and just return their first operand. 663 | unary_operands(llvm_inst, ctx, strings) 664 | } 665 | "llvm.objectsize.i8.p0i8" 666 | | "llvm.objectsize.i16.p0i8" 667 | | "llvm.objectsize.i32.p0i8" 668 | | "llvm.objectsize.i64.p0i8" => { 669 | let min = unsafe { LLVMConstIntGetZExtValue(LLVMGetOperand(llvm_inst, 1)) } != 0; 670 | let ty = translate_type_of(llvm_inst, ctx.dl); 671 | ctx.builder 672 | .ins() 673 | .iconst(ty, ir::immediates::Imm64::new(if min { 0 } else { -1 })) 674 | } 675 | "llvm.sqrt.f32" | "llvm.sqrt.f64" => { 676 | let op = unary_operands(llvm_inst, ctx, strings); 677 | ctx.builder.ins().sqrt(op) 678 | } 679 | "llvm.fabs.f32" | "llvm.fabs.f64" => { 680 | let op = unary_operands(llvm_inst, ctx, strings); 681 | ctx.builder.ins().fabs(op) 682 | } 683 | "llvm.copysign.f32" | "llvm.copysign.f64" => { 684 | let (lhs, rhs) = binary_operands(llvm_inst, ctx, strings); 685 | ctx.builder.ins().fcopysign(lhs, rhs) 686 | } 687 | "llvm.ceil.f32" | "llvm.ceil.f64" => { 688 | let op = unary_operands(llvm_inst, ctx, strings); 689 | ctx.builder.ins().ceil(op) 690 | } 691 | "llvm.floor.f32" | "llvm.floor.f64" => { 692 | let op = unary_operands(llvm_inst, ctx, strings); 693 | ctx.builder.ins().floor(op) 694 | } 695 | "llvm.trunc.f32" | "llvm.trunc.f64" => { 696 | let op = unary_operands(llvm_inst, ctx, strings); 697 | ctx.builder.ins().trunc(op) 698 | } 699 | "llvm.nearbyint.f32" | "llvm.nearbyint.f64" => { 700 | let op = unary_operands(llvm_inst, ctx, strings); 701 | ctx.builder.ins().nearest(op) 702 | } 703 | "llvm.ctpop.i8" | "llvm.ctpop.i16" | "llvm.ctpop.i32" | "llvm.ctpop.i64" => { 704 | let op = unary_operands(llvm_inst, ctx, strings); 705 | ctx.builder.ins().popcnt(op) 706 | } 707 | "llvm.ctlz.i8" | "llvm.ctlz.i16" | "llvm.ctlz.i32" | "llvm.ctlz.i64" => { 708 | let op = unary_operands(llvm_inst, ctx, strings); 709 | ctx.builder.ins().clz(op) 710 | } 711 | "llvm.cttz.i8" | "llvm.cttz.i16" | "llvm.cttz.i32" | "llvm.cttz.i64" => { 712 | let op = unary_operands(llvm_inst, ctx, strings); 713 | ctx.builder.ins().ctz(op) 714 | } 715 | "llvm.trap" => { 716 | // This intrinsic isn't a terminator in LLVM IR, but trap is a 717 | // terminator in Cranelift. After the trap, start a new basic block. 718 | ctx.builder.ins().trap(ir::TrapCode::User(1)); 719 | let ebb = ctx.builder.create_ebb(); 720 | ctx.builder.seal_block(ebb); 721 | ctx.builder.switch_to_block(ebb); 722 | return None; 723 | } 724 | "llvm.debugtrap" => { 725 | // See the comment on "llvm.trap". 726 | ctx.builder.ins().trap(ir::TrapCode::User(2)); 727 | let ebb = ctx.builder.create_ebb(); 728 | ctx.builder.seal_block(ebb); 729 | ctx.builder.switch_to_block(ebb); 730 | return None; 731 | } 732 | "llvm.fmuladd.f32" | "llvm.fmuladd.f64" => { 733 | // Cranelift currently has no fma instruction, so just lower these 734 | // as non-fused operations. 735 | let (a, b, c) = ternary_operands(llvm_inst, ctx, strings); 736 | let t = ctx.builder.ins().fmul(a, b); 737 | ctx.builder.ins().fadd(t, c) 738 | } 739 | "llvm.minnum.f32" => translate_intr_libcall("fminf", llvm_inst, llvm_callee, ctx, strings), 740 | "llvm.minnum.f64" => translate_intr_libcall("fmin", llvm_inst, llvm_callee, ctx, strings), 741 | "llvm.maxnum.f32" => translate_intr_libcall("fmaxf", llvm_inst, llvm_callee, ctx, strings), 742 | "llvm.maxnum.f64" => translate_intr_libcall("fmax", llvm_inst, llvm_callee, ctx, strings), 743 | "llvm.sin.f32" => translate_intr_libcall("sinf", llvm_inst, llvm_callee, ctx, strings), 744 | "llvm.sin.f64" => translate_intr_libcall("sin", llvm_inst, llvm_callee, ctx, strings), 745 | "llvm.cos.f32" => translate_intr_libcall("cosf", llvm_inst, llvm_callee, ctx, strings), 746 | "llvm.cos.f64" => translate_intr_libcall("cos", llvm_inst, llvm_callee, ctx, strings), 747 | "llvm.tan.f32" => translate_intr_libcall("tanf", llvm_inst, llvm_callee, ctx, strings), 748 | "llvm.tan.f64" => translate_intr_libcall("tan", llvm_inst, llvm_callee, ctx, strings), 749 | "llvm.exp.f32" => translate_intr_libcall("expf", llvm_inst, llvm_callee, ctx, strings), 750 | "llvm.exp.f64" => translate_intr_libcall("exp", llvm_inst, llvm_callee, ctx, strings), 751 | "llvm.exp2.f32" => translate_intr_libcall("exp2f", llvm_inst, llvm_callee, ctx, strings), 752 | "llvm.exp2.f64" => translate_intr_libcall("exp2", llvm_inst, llvm_callee, ctx, strings), 753 | "llvm.log.f32" => translate_intr_libcall("logf", llvm_inst, llvm_callee, ctx, strings), 754 | "llvm.log.f64" => translate_intr_libcall("log", llvm_inst, llvm_callee, ctx, strings), 755 | "llvm.log2.f32" => translate_intr_libcall("log2f", llvm_inst, llvm_callee, ctx, strings), 756 | "llvm.log2.f64" => translate_intr_libcall("log2", llvm_inst, llvm_callee, ctx, strings), 757 | "llvm.log10.f32" => translate_intr_libcall("log10f", llvm_inst, llvm_callee, ctx, strings), 758 | "llvm.log10.f64" => translate_intr_libcall("log10", llvm_inst, llvm_callee, ctx, strings), 759 | "llvm.pow.f32" => translate_intr_libcall("powf", llvm_inst, llvm_callee, ctx, strings), 760 | "llvm.pow.f64" => translate_intr_libcall("pow", llvm_inst, llvm_callee, ctx, strings), 761 | "llvm.rint.f32" => translate_intr_libcall("rintf", llvm_inst, llvm_callee, ctx, strings), 762 | "llvm.rint.f64" => translate_intr_libcall("rint", llvm_inst, llvm_callee, ctx, strings), 763 | "llvm.round.f32" => translate_intr_libcall("roundf", llvm_inst, llvm_callee, ctx, strings), 764 | "llvm.round.f64" => translate_intr_libcall("round", llvm_inst, llvm_callee, ctx, strings), 765 | "llvm.fma.f32" => translate_intr_libcall("fmaf", llvm_inst, llvm_callee, ctx, strings), 766 | "llvm.fma.f64" => translate_intr_libcall("fma", llvm_inst, llvm_callee, ctx, strings), 767 | "llvm.memcpy.p0i8.p0i8.i8" 768 | | "llvm.memcpy.p0i8.p0i8.i16" 769 | | "llvm.memcpy.p0i8.p0i8.i32" 770 | | "llvm.memcpy.p0i8.p0i8.i64" => { 771 | translate_mem_intrinsic("memcpy", llvm_inst, ctx, strings); 772 | return None; 773 | } 774 | "llvm.memmove.p0i8.p0i8.i8" 775 | | "llvm.memmove.p0i8.p0i8.i16" 776 | | "llvm.memmove.p0i8.p0i8.i32" 777 | | "llvm.memmove.p0i8.p0i8.i64" => { 778 | translate_mem_intrinsic("memmove", llvm_inst, ctx, strings); 779 | return None; 780 | } 781 | "llvm.memset.p0i8.i8" 782 | | "llvm.memset.p0i8.i16" 783 | | "llvm.memset.p0i8.i32" 784 | | "llvm.memset.p0i8.i64" => { 785 | translate_mem_intrinsic("memset", llvm_inst, ctx, strings); 786 | return None; 787 | } 788 | _ => panic!("unimplemented: intrinsic: {}", name), 789 | }) 790 | } 791 | 792 | /// Translate an LLVM IR intrinsic call which corresponds directly to a 793 | /// C library call. 794 | fn translate_intr_libcall( 795 | name: &str, 796 | llvm_inst: LLVMValueRef, 797 | llvm_callee: LLVMValueRef, 798 | ctx: &mut Context, 799 | strings: &StringTable, 800 | ) -> ir::Value { 801 | let num_args = unsafe { LLVMGetNumArgOperands(llvm_inst) } as usize; 802 | let mut args = Vec::with_capacity(num_args); 803 | for i in 0..num_args { 804 | debug_assert_eq!(i as libc::c_uint as usize, i); 805 | args.push(use_val( 806 | unsafe { LLVMGetOperand(llvm_inst, i as libc::c_uint) }, 807 | ctx, 808 | strings, 809 | )); 810 | } 811 | 812 | let name = strings.get_extname(name); 813 | let signature = ctx.builder.import_signature(translate_sig( 814 | unsafe { LLVMGetElementType(LLVMTypeOf(llvm_callee)) }, 815 | ctx.dl, 816 | )); 817 | let data = ir::ExtFuncData { 818 | name, 819 | signature, 820 | colocated: false, // TODO: Set the colocated flag based on the visibility. 821 | }; 822 | let callee = ctx.builder.import_function(data); 823 | let call = ctx.builder.ins().call(callee, &args); 824 | let results = ctx.builder.inst_results(call); 825 | debug_assert_eq!(results.len(), 1); 826 | results[0] 827 | } 828 | 829 | /// Translate an LLVM IR llvm.memcpy/memmove/memset call. 830 | fn translate_mem_intrinsic( 831 | name: &str, 832 | llvm_inst: LLVMValueRef, 833 | ctx: &mut Context, 834 | strings: &StringTable, 835 | ) { 836 | let pointer_type = translate_pointer_type(ctx.dl); 837 | 838 | let dst_arg = use_val(unsafe { LLVMGetOperand(llvm_inst, 0) }, ctx, strings); 839 | 840 | let llvm_src_arg = unsafe { LLVMGetOperand(llvm_inst, 1) }; 841 | let orig_src_arg = use_val(llvm_src_arg, ctx, strings); 842 | let src_arg = if name == "memset" { 843 | ctx.builder.ins().uextend(ir::types::I32, orig_src_arg) 844 | } else { 845 | orig_src_arg 846 | }; 847 | 848 | let llvm_len_arg = unsafe { LLVMGetOperand(llvm_inst, 2) }; 849 | let len_arg = unsigned_cast( 850 | translate_type_of(llvm_len_arg, ctx.dl), 851 | pointer_type, 852 | use_val(llvm_len_arg, ctx, strings), 853 | ctx, 854 | ); 855 | 856 | // Discard the alignment hint for now. 857 | // Discard the volatile flag too, which is safe as long as Cranelift doesn't 858 | // start optimizing these libcalls. 859 | let args = [dst_arg, src_arg, len_arg]; 860 | 861 | let funcname = strings.get_extname(name); 862 | // TODO: Translate the calling convention. 863 | let mut sig = ir::Signature::new(CallConv::SystemV); 864 | sig.params.resize(3, ir::AbiParam::new(pointer_type)); 865 | if name == "memset" { 866 | sig.params[1] = ir::AbiParam::new(ir::types::I32); 867 | } 868 | sig.returns.resize(1, ir::AbiParam::new(pointer_type)); 869 | let signature = ctx.builder.import_signature(sig); 870 | let data = ir::ExtFuncData { 871 | name: funcname, 872 | signature, 873 | colocated: false, // TODO: Set the colocated flag based on the visibility. 874 | }; 875 | let callee = ctx.builder.import_function(data); 876 | ctx.builder.ins().call(callee, &args); 877 | } 878 | 879 | /// Record PHI uses and defs for a branch from `llvm_bb` to `llvm_succ`. 880 | fn handle_phi_operands( 881 | llvm_bb: LLVMBasicBlockRef, 882 | llvm_succ: LLVMBasicBlockRef, 883 | ctx: &mut Context, 884 | strings: &StringTable, 885 | ) { 886 | let mut defs = Vec::new(); 887 | 888 | let mut llvm_inst = unsafe { LLVMGetFirstInstruction(llvm_succ) }; 889 | while !llvm_inst.is_null() { 890 | if let LLVMPHI = unsafe { LLVMGetInstructionOpcode(llvm_inst) } { 891 | // TODO: We'd really want getBasicBlockIndex or getIncomingValueForBlock 892 | // here, but LLVM's C API doesn't expose those currently. 893 | let mut llvm_val = ptr::null_mut(); 894 | for i in 0..unsafe { LLVMCountIncoming(llvm_inst) } { 895 | if unsafe { LLVMGetIncomingBlock(llvm_inst, i) } == llvm_bb { 896 | llvm_val = unsafe { LLVMGetIncomingValue(llvm_inst, i) }; 897 | break; 898 | } 899 | } 900 | 901 | let val = use_val(llvm_val, ctx, strings); 902 | defs.push((llvm_inst, val)); 903 | } else { 904 | break; 905 | } 906 | llvm_inst = unsafe { LLVMGetNextInstruction(llvm_inst) }; 907 | } 908 | 909 | for (llvm_inst, val) in defs { 910 | def_val(llvm_inst, val, ctx); 911 | } 912 | } 913 | 914 | /// Translate a GetElementPtr index operand into Cranelift IL. 915 | fn translate_gep_index( 916 | llvm_gepty: LLVMTypeRef, 917 | ptr: ir::Value, 918 | imm: i64, 919 | pointer_type: ir::Type, 920 | index: LLVMValueRef, 921 | ctx: &mut Context, 922 | strings: &StringTable, 923 | ) -> (LLVMTypeRef, ir::Value, i64) { 924 | // TODO: We'd really want gep_type_iterator etc. here, but 925 | // LLVM's C API doesn't expose those currently. 926 | let (offset, ty) = match unsafe { LLVMGetTypeKind(llvm_gepty) } { 927 | LLVMStructTypeKind => { 928 | let i = unsafe { LLVMConstIntGetZExtValue(index) }; 929 | debug_assert_eq!(u64::from(i as libc::c_uint), i); 930 | let llvm_eltty = unsafe { LLVMStructGetTypeAtIndex(llvm_gepty, i as libc::c_uint) }; 931 | let imm_offset = 932 | unsafe { LLVMOffsetOfElement(ctx.dl, llvm_gepty, i as libc::c_uint) } as i64; 933 | return (llvm_eltty, ptr, imm.wrapping_add(imm_offset)); 934 | } 935 | LLVMPointerTypeKind | LLVMArrayTypeKind | LLVMVectorTypeKind => { 936 | let llvm_eltty = unsafe { LLVMGetElementType(llvm_gepty) }; 937 | let size = unsafe { LLVMABISizeOfType(ctx.dl, llvm_eltty) }; 938 | 939 | if unsafe { LLVMIsConstant(index) } != 0 { 940 | let index_val = unsafe { LLVMConstIntGetSExtValue(index) }; 941 | let imm_offset = index_val.wrapping_mul(size as i64); 942 | return (llvm_eltty, ptr, imm.wrapping_add(imm_offset)); 943 | } 944 | 945 | let index_type = translate_type_of(index, ctx.dl); 946 | let mut x = use_val(index, ctx, strings); 947 | if index_type != pointer_type { 948 | if index_type.is_bool() { 949 | x = ctx.builder.ins().bmask(pointer_type, x); 950 | } else if index_type.bits() < pointer_type.bits() { 951 | x = ctx.builder.ins().sextend(pointer_type, x); 952 | } else { 953 | x = ctx.builder.ins().ireduce(pointer_type, x); 954 | } 955 | } 956 | 957 | if size != 1 { 958 | x = ctx.builder 959 | .ins() 960 | .imul_imm(x, ir::immediates::Imm64::new(size as i64)); 961 | } 962 | 963 | (x, llvm_eltty) 964 | } 965 | _ => panic!("unexpected GEP indexing type: {:?}", llvm_gepty), 966 | }; 967 | (ty, ctx.builder.ins().iadd(ptr, offset), imm) 968 | } 969 | 970 | /// Emit a Cranelift jump to the destination corresponding to `llvm_succ`, if 971 | /// one is needed. 972 | fn jump( 973 | llvm_bb: LLVMBasicBlockRef, 974 | llvm_succ: LLVMBasicBlockRef, 975 | ctx: &mut Context, 976 | strings: &StringTable, 977 | ) { 978 | if let Some(&ebb) = ctx.ebb_map.get(&llvm_succ) { 979 | handle_phi_operands(llvm_bb, llvm_succ, ctx, strings); 980 | ctx.builder.ins().jump(ebb, &[]); 981 | } 982 | } 983 | 984 | fn translate_bool_cmp( 985 | condcode: ir::condcodes::IntCC, 986 | lhs: ir::Value, 987 | rhs: ir::Value, 988 | ctx: &mut Context, 989 | ) -> ir::Value { 990 | match condcode { 991 | ir::condcodes::IntCC::Equal => ctx.builder.ins().bxor_not(lhs, rhs), 992 | ir::condcodes::IntCC::NotEqual => ctx.builder.ins().bxor(lhs, rhs), 993 | ir::condcodes::IntCC::SignedLessThan => ctx.builder.ins().band_not(lhs, rhs), 994 | ir::condcodes::IntCC::SignedLessThanOrEqual => ctx.builder.ins().bor_not(lhs, rhs), 995 | ir::condcodes::IntCC::SignedGreaterThan => ctx.builder.ins().band_not(rhs, lhs), 996 | ir::condcodes::IntCC::SignedGreaterThanOrEqual => ctx.builder.ins().bor_not(rhs, lhs), 997 | ir::condcodes::IntCC::UnsignedLessThan => ctx.builder.ins().band_not(rhs, lhs), 998 | ir::condcodes::IntCC::UnsignedLessThanOrEqual => ctx.builder.ins().bor_not(rhs, lhs), 999 | ir::condcodes::IntCC::UnsignedGreaterThan => ctx.builder.ins().band_not(lhs, rhs), 1000 | ir::condcodes::IntCC::UnsignedGreaterThanOrEqual => ctx.builder.ins().bor_not(lhs, rhs), 1001 | } 1002 | } 1003 | 1004 | fn unsigned_cast( 1005 | from: ir::types::Type, 1006 | to: ir::types::Type, 1007 | op: ir::Value, 1008 | ctx: &mut Context, 1009 | ) -> ir::Value { 1010 | if from == to { 1011 | // No-op cast. 1012 | op 1013 | } else if from.bits() > to.bits() { 1014 | if to.is_bool() { 1015 | let band = ctx.builder.ins().band_imm(op, 1); 1016 | ctx.builder 1017 | .ins() 1018 | .icmp_imm(ir::condcodes::IntCC::NotEqual, band, 0) 1019 | } else { 1020 | ctx.builder.ins().ireduce(to, op) 1021 | } 1022 | } else { 1023 | if from.is_bool() { 1024 | ctx.builder.ins().bint(to, op) 1025 | } else { 1026 | ctx.builder.ins().uextend(to, op) 1027 | } 1028 | } 1029 | } 1030 | 1031 | /// Record a "use" of an LLVM IR value. 1032 | fn use_val(llvm_val: LLVMValueRef, ctx: &mut Context, strings: &StringTable) -> ir::Value { 1033 | if unsafe { LLVMIsConstant(llvm_val) } != 0 { 1034 | materialize_constant(llvm_val, ctx, strings) 1035 | } else { 1036 | let num_values = ctx.value_map.len(); 1037 | let var = match ctx.value_map.entry(llvm_val) { 1038 | hash_map::Entry::Occupied(entry) => *entry.get(), 1039 | hash_map::Entry::Vacant(entry) => { 1040 | let var = Variable::new(num_values); 1041 | let ty = translate_type_of(llvm_val, ctx.dl); 1042 | ctx.builder.declare_var(var, ty); 1043 | *entry.insert(var) 1044 | } 1045 | }; 1046 | ctx.builder.use_var(var) 1047 | } 1048 | } 1049 | 1050 | /// Record a "definition" of an LLVM IR value. 1051 | fn def_val(llvm_val: LLVMValueRef, value: ir::Value, ctx: &mut Context) { 1052 | if unsafe { LLVMIsConstant(llvm_val) } != 0 { 1053 | // Do nothing. In use_val, we special-case constants and materialize 1054 | // them for each use. 1055 | } else { 1056 | let num_values = ctx.value_map.len(); 1057 | let var = match ctx.value_map.entry(llvm_val) { 1058 | hash_map::Entry::Occupied(entry) => *entry.get(), 1059 | hash_map::Entry::Vacant(entry) => { 1060 | let var = Variable::new(num_values); 1061 | let ty = translate_type_of(llvm_val, ctx.dl); 1062 | ctx.builder.declare_var(var, ty); 1063 | *entry.insert(var) 1064 | } 1065 | }; 1066 | ctx.builder.def_var(var, value) 1067 | } 1068 | } 1069 | 1070 | /// Translate the operands for a unary operation. 1071 | fn unary_operands(llvm_val: LLVMValueRef, ctx: &mut Context, strings: &StringTable) -> ir::Value { 1072 | use_val(unsafe { LLVMGetOperand(llvm_val, 0) }, ctx, strings) 1073 | } 1074 | 1075 | /// A boolean operation with two register inputs, an integer operation 1076 | /// with two register operands, or an integer operation with a register 1077 | /// operand and an immediate operand. 1078 | enum RegImmOperands { 1079 | Bool(ir::Value, ir::Value), 1080 | RegReg(ir::Value, ir::Value), 1081 | RegImm(ir::Value, ir::immediates::Imm64), 1082 | } 1083 | 1084 | /// Translate the operands for a binary operation taking one register and 1085 | /// one operand which may be either a register or an immediate. 1086 | /// 1087 | /// Using the `*_imm` forms of instructions isn't necessary, as Cranelift 1088 | /// should fold constants into immediates just as well, but doing it in 1089 | /// translation makes the output tidier and exercises more of the 1090 | /// builder API. 1091 | fn binary_operands_r_ri( 1092 | llvm_val: LLVMValueRef, 1093 | ctx: &mut Context, 1094 | strings: &StringTable, 1095 | ) -> RegImmOperands { 1096 | // For most instructions, we don't need to check whether the lhs is 1097 | // a constant, because constants are canonicalized the the rhs when 1098 | // possible. 1099 | let lhs = use_val(unsafe { LLVMGetOperand(llvm_val, 0) }, ctx, strings); 1100 | 1101 | // Optimize the rhs if it's a constant and not boolean, since Cranelift's 1102 | // `*_imm` instructions don't support boolean types. 1103 | let llvm_rhs = unsafe { LLVMGetOperand(llvm_val, 1) }; 1104 | let llvm_rhs_type = unsafe { LLVMTypeOf(llvm_rhs) }; 1105 | if unsafe { LLVMGetIntTypeWidth(llvm_rhs_type) } == 1 { 1106 | RegImmOperands::Bool(lhs, use_val(llvm_rhs, ctx, strings)) 1107 | } else if unsafe { LLVMIsNull(llvm_rhs) } != 0 { 1108 | RegImmOperands::RegImm( 1109 | lhs, 1110 | ir::immediates::Imm64::from(0), 1111 | ) 1112 | } else if unsafe { LLVMIsConstant(llvm_rhs) } != 0 1113 | && unsafe { LLVMGetValueKind(llvm_rhs) } == LLVMConstantIntValueKind 1114 | { 1115 | RegImmOperands::RegImm( 1116 | lhs, 1117 | ir::immediates::Imm64::from(unsafe { LLVMConstIntGetZExtValue(llvm_rhs) } as i64), 1118 | ) 1119 | } else { 1120 | RegImmOperands::RegReg(lhs, use_val(llvm_rhs, ctx, strings)) 1121 | } 1122 | } 1123 | 1124 | /// Translate the operands for a binary operation. 1125 | fn binary_operands( 1126 | llvm_val: LLVMValueRef, 1127 | ctx: &mut Context, 1128 | strings: &StringTable, 1129 | ) -> (ir::Value, ir::Value) { 1130 | ( 1131 | use_val(unsafe { LLVMGetOperand(llvm_val, 0) }, ctx, strings), 1132 | use_val(unsafe { LLVMGetOperand(llvm_val, 1) }, ctx, strings), 1133 | ) 1134 | } 1135 | 1136 | /// Translate the operands for a binary operation. 1137 | fn ternary_operands( 1138 | llvm_val: LLVMValueRef, 1139 | ctx: &mut Context, 1140 | strings: &StringTable, 1141 | ) -> (ir::Value, ir::Value, ir::Value) { 1142 | ( 1143 | use_val(unsafe { LLVMGetOperand(llvm_val, 0) }, ctx, strings), 1144 | use_val(unsafe { LLVMGetOperand(llvm_val, 1) }, ctx, strings), 1145 | use_val(unsafe { LLVMGetOperand(llvm_val, 2) }, ctx, strings), 1146 | ) 1147 | } 1148 | 1149 | /// Return the successor of `llvm_inst` with index `i`. 1150 | fn successor(llvm_inst: LLVMValueRef, i: ::libc::c_uint) -> LLVMBasicBlockRef { 1151 | unsafe { LLVMGetSuccessor(llvm_inst, i) } 1152 | } 1153 | 1154 | /// Translate an LLVM integer predicate into a Cranelift one. 1155 | fn translate_icmp_code(llvm_pred: LLVMIntPredicate) -> ir::condcodes::IntCC { 1156 | match llvm_pred { 1157 | LLVMIntEQ => ir::condcodes::IntCC::Equal, 1158 | LLVMIntNE => ir::condcodes::IntCC::NotEqual, 1159 | LLVMIntUGT => ir::condcodes::IntCC::UnsignedGreaterThan, 1160 | LLVMIntUGE => ir::condcodes::IntCC::UnsignedGreaterThanOrEqual, 1161 | LLVMIntULT => ir::condcodes::IntCC::UnsignedLessThan, 1162 | LLVMIntULE => ir::condcodes::IntCC::UnsignedLessThanOrEqual, 1163 | LLVMIntSGT => ir::condcodes::IntCC::SignedGreaterThan, 1164 | LLVMIntSGE => ir::condcodes::IntCC::SignedGreaterThanOrEqual, 1165 | LLVMIntSLT => ir::condcodes::IntCC::SignedLessThan, 1166 | LLVMIntSLE => ir::condcodes::IntCC::SignedLessThanOrEqual, 1167 | } 1168 | } 1169 | 1170 | /// Translate an LLVM floating-point predicate into a Cranelift one. 1171 | fn translate_fcmp_code(llvm_pred: LLVMRealPredicate) -> ir::condcodes::FloatCC { 1172 | match llvm_pred { 1173 | LLVMRealOEQ => ir::condcodes::FloatCC::Equal, 1174 | LLVMRealOGT => ir::condcodes::FloatCC::GreaterThan, 1175 | LLVMRealOGE => ir::condcodes::FloatCC::GreaterThanOrEqual, 1176 | LLVMRealOLT => ir::condcodes::FloatCC::LessThan, 1177 | LLVMRealOLE => ir::condcodes::FloatCC::LessThanOrEqual, 1178 | LLVMRealONE => ir::condcodes::FloatCC::OrderedNotEqual, 1179 | LLVMRealORD => ir::condcodes::FloatCC::Ordered, 1180 | LLVMRealUNO => ir::condcodes::FloatCC::Unordered, 1181 | LLVMRealUEQ => ir::condcodes::FloatCC::UnorderedOrEqual, 1182 | LLVMRealUGT => ir::condcodes::FloatCC::UnorderedOrGreaterThan, 1183 | LLVMRealUGE => ir::condcodes::FloatCC::UnorderedOrGreaterThanOrEqual, 1184 | LLVMRealULT => ir::condcodes::FloatCC::UnorderedOrLessThan, 1185 | LLVMRealULE => ir::condcodes::FloatCC::UnorderedOrLessThanOrEqual, 1186 | LLVMRealUNE => ir::condcodes::FloatCC::NotEqual, 1187 | LLVMRealPredicateFalse | LLVMRealPredicateTrue => panic!(), 1188 | } 1189 | } 1190 | 1191 | /// Translate LLVM load/store information into Cranelift `MemFlags`. 1192 | fn translate_memflags( 1193 | llvm_inst: LLVMValueRef, 1194 | llvm_ty: LLVMTypeRef, 1195 | ctx: &Context, 1196 | ) -> ir::MemFlags { 1197 | if unsafe { LLVMGetVolatile(llvm_inst) } != 0 { 1198 | panic!("unimplemented: volatile memory reference"); 1199 | } 1200 | if unsafe { LLVMGetOrdering(llvm_inst) } != LLVMAtomicOrderingNotAtomic { 1201 | panic!("unimplemented: atomic memory reference"); 1202 | } 1203 | 1204 | let mut flags = ir::MemFlags::new(); 1205 | 1206 | // LLVM IR has UB. 1207 | flags.set_notrap(); 1208 | 1209 | if u64::from(unsafe { LLVMGetAlignment(llvm_inst) }) 1210 | >= unsafe { LLVMABISizeOfType(ctx.dl, llvm_ty) } 1211 | { 1212 | flags.set_aligned(); 1213 | } 1214 | 1215 | flags 1216 | } 1217 | 1218 | /// Translate the type of an LLVM Value into a Cranelift type. 1219 | fn translate_type_of(llvm_val: LLVMValueRef, dl: LLVMTargetDataRef) -> ir::Type { 1220 | translate_type(unsafe { LLVMTypeOf(llvm_val) }, dl) 1221 | } 1222 | --------------------------------------------------------------------------------