use super::*;
use super::c_api::*;
use std::path::Path;
use std::ptr::null_mut;
use llvm_sys::target::*;
use llvm_sys::target_machine::*;
static mut UNINITIALIZED: bool = true;
unsafe fn initialize() {
if UNINITIALIZED {
UNINITIALIZED = false;
LLVM_InitializeAllTargets();
LLVM_InitializeAllTargetInfos();
LLVM_InitializeAllTargetMCs();
}
}
pub fn default_triple() -> String {
from_c(unsafe {
LLVMGetDefaultTargetTriple()
}).unwrap_or(String::new())
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum OptLevel {
None = 0,
Less = 1,
Default = 2,
Aggressive = 3,
}
impl OptLevel {
pub unsafe fn inner(&self) -> LLVMCodeGenOptLevel {
use llvm_sys::target_machine::LLVMCodeGenOptLevel::*;
use self::OptLevel::*;
match self {
&None => LLVMCodeGenLevelNone,
&Less => LLVMCodeGenLevelLess,
&Default => LLVMCodeGenLevelDefault,
&Aggressive => LLVMCodeGenLevelAggressive,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FileType {
Assembly,
Object,
}
impl FileType {
pub fn inner(&self) -> LLVMCodeGenFileType {
use llvm_sys::target_machine::LLVMCodeGenFileType::*;
use self::FileType::*;
match self {
&Assembly => LLVMAssemblyFile,
&Object => LLVMObjectFile,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ByteOrdering {
BigEndian,
LittleEndian,
}
impl ByteOrdering {
pub fn inner(&self) -> LLVMByteOrdering {
use llvm_sys::target::LLVMByteOrdering::*;
use self::ByteOrdering::*;
match self {
&BigEndian => LLVMBigEndian,
&LittleEndian => LLVMLittleEndian,
}
}
}
#[derive(Copy, Clone)]
pub struct Target {
target: LLVMTargetRef,
}
impl Target {
pub fn from_triple(triple: String) -> Result<Target, String> {
unsafe {
initialize();
let mut target: LLVMTargetRef = null_mut();
let mut error = null_mut();
if LLVMGetTargetFromTriple(
into_c(triple).as_ptr(),
&mut target as *mut LLVMTargetRef,
&mut error as *mut *mut i8,
) == 1 || target.is_null() {
Err(from_c(error).unwrap_or(String::new()))
} else {
Ok(Target {
target,
})
}
}
}
pub fn create_machine(&self, triple: String) -> TargetMachine {
self.create_machine_with_options(triple, "generic".to_owned(), String::new(), OptLevel::Default)
}
pub fn create_machine_with_options(&self, triple: String, cpu: String, features: String,
level: OptLevel) -> TargetMachine {
TargetMachine {
machine: unsafe {
LLVMCreateTargetMachine(
self.target,
into_c(triple).as_ptr(),
into_c(cpu).as_ptr(),
into_c(features).as_ptr(),
level.inner(),
LLVMRelocMode::LLVMRelocDefault,
LLVMCodeModel::LLVMCodeModelDefault,
)
}
}
}
pub fn name(&self) -> String {
unsafe {
from_c(LLVMGetTargetName(self.target)).unwrap_or(String::new())
}
}
pub fn description(&self) -> String {
unsafe {
from_c(LLVMGetTargetDescription(self.target)).unwrap_or(String::new())
}
}
}
impl Debug for Target {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Target({:?}, {:?})", self.name(), self.description())
}
}
impl Display for Target {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[derive(Clone)]
pub struct TargetMachine {
machine: LLVMTargetMachineRef,
}
impl TargetMachine {
pub fn native() -> Result<TargetMachine, String> {
TargetMachine::new(default_triple())
}
pub fn new(triple: String) -> Result<TargetMachine, String> {
Ok(Target::from_triple(triple.clone())?.create_machine(triple))
}
pub fn new_with_options(triple: String, cpu: String, features: String,
level: OptLevel) -> Result<TargetMachine, String> {
Ok(Target::from_triple(triple.clone())?.create_machine_with_options(triple, cpu, features, level))
}
pub fn emit_module_to_file<P>(&self, module: &Module, file: P, file_type: FileType) -> Result<(), String>
where P: AsRef<Path> {
unsafe {
LLVM_InitializeAllAsmPrinters();
let file_str = into_c(file.as_ref().to_str().expect("invalid path")).into_raw();
let mut error = null_mut();
let flag = LLVMTargetMachineEmitToFile(
self.machine,
module.module.unwrap(),
file_str,
file_type.inner(),
&mut error as *mut *mut i8,
) == 1;
CString::from_raw(file_str);
if flag {
Err(from_c(error).unwrap_or(String::new()))
} else {
Ok(())
}
}
}
pub fn data_layout(&self) -> TargetData {
TargetData {
data: unsafe {
LLVMCreateTargetDataLayout(self.machine)
}
}
}
pub fn target(&self) -> Target {
Target {
target: unsafe{
LLVMGetTargetMachineTarget(self.machine)
}
}
}
pub fn triple(&self) -> String {
unsafe {
from_c(LLVMGetTargetMachineTriple(self.machine)).unwrap_or(String::new())
}
}
pub fn cpu(&self) -> String {
unsafe {
from_c(LLVMGetTargetMachineCPU(self.machine)).unwrap_or(String::new())
}
}
pub fn features(&self) -> String {
unsafe {
from_c(LLVMGetTargetMachineFeatureString(self.machine)).unwrap_or(String::new())
}
}
}
impl Debug for TargetMachine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TargetMachine({:?}, {:?}, {:?}, {:?})", self.target(), self.triple(), self.cpu(), self.features())
}
}
impl Drop for TargetMachine {
fn drop(&mut self) {
unsafe {
LLVMDisposeTargetMachine(self.machine);
}
}
}
#[derive(Clone)]
pub struct TargetData {
pub(crate) data: LLVMTargetDataRef,
}
impl TargetData {
pub fn byte_order(&self) -> ByteOrdering {
unsafe {
use llvm_sys::target::LLVMByteOrdering::*;
use self::ByteOrdering::*;
match LLVMByteOrder(self.data) {
LLVMBigEndian => BigEndian,
LLVMLittleEndian => LittleEndian,
}
}
}
pub fn size_of_ptr(&self) -> u64 {
unsafe {
LLVMPointerSize(self.data) as u64
}
}
pub fn bit_size_of_ptr(&self) -> u64 {
unsafe {
LLVMPointerSize(self.data) as u64 * 8
}
}
pub fn offset_of_element(&self, ty: Type, index: u32) -> u64 {
unsafe {
LLVMOffsetOfElement(self.data, ty.ty, index)
}
}
pub fn element_at_offset(&self, ty: Type, offset: u64) -> u32 {
unsafe {
LLVMElementAtOffset(self.data, ty.ty, offset)
}
}
pub fn size_of(&self, ty: Type) -> u64 {
unsafe {
LLVMABISizeOfType(self.data, ty.ty)
}
}
pub fn bit_size_of(&self, ty: Type) -> u64 {
unsafe {
LLVMSizeOfTypeInBits(self.data, ty.ty)
}
}
pub fn store_size_of(&self, ty: Type) -> u64 {
unsafe {
LLVMStoreSizeOfType(self.data, ty.ty)
}
}
pub fn abi_alignment_of(&self, ty: Type) -> u32 {
unsafe {
LLVMABIAlignmentOfType(self.data, ty.ty)
}
}
pub fn call_frame_alignment_of(&self, ty: Type) -> u32 {
unsafe {
LLVMCallFrameAlignmentOfType(self.data, ty.ty)
}
}
pub fn preferred_alignment_of(&self, ty: Type) -> u32 {
unsafe {
LLVMPreferredAlignmentOfType(self.data, ty.ty)
}
}
}
impl Debug for TargetData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TargetData({:?})", self.to_string())
}
}
impl Display for TargetData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", unsafe {
from_c(LLVMCopyStringRepOfTargetData(self.data)).unwrap_or(String::new())
})
}
}
impl Drop for TargetData {
fn drop(&mut self) {
unsafe {
LLVMDisposeTargetData(self.data);
}
}
}