diff options
| author | Jyun-Yan You <jyyou@cs.nctu.edu.tw> | 2013-01-30 01:31:50 +0800 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2013-03-03 20:02:03 -0800 |
| commit | c2a61d7df33acc606209b0b020208c7f20212394 (patch) | |
| tree | e24e89162eb315633119e4252252e86498d1066d | |
| parent | 5150b9811b520843e7a4905da4e6030b5f7ff9fd (diff) | |
| download | rust-c2a61d7df33acc606209b0b020208c7f20212394.tar.gz rust-c2a61d7df33acc606209b0b020208c7f20212394.zip | |
rustc: implement MIPS O32 ABI
| -rw-r--r-- | src/librustc/back/mips.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/trans/cabi_mips.rs | 221 | ||||
| -rw-r--r-- | src/librustc/middle/trans/foreign.rs | 3 | ||||
| -rw-r--r-- | src/librustc/rustc.rc | 1 |
4 files changed, 226 insertions, 1 deletions
diff --git a/src/librustc/back/mips.rs b/src/librustc/back/mips.rs index 32d434ed49d..93c1879eb0f 100644 --- a/src/librustc/back/mips.rs +++ b/src/librustc/back/mips.rs @@ -10,7 +10,7 @@ use back::target_strs; use driver::session; -use session::sess_os_to_meta_os; +use driver::session::sess_os_to_meta_os; use metadata::loader::meta_section_name; pub fn get_target_strs(target_os: session::os) -> target_strs::t { diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs new file mode 100644 index 00000000000..4f5e9edb126 --- /dev/null +++ b/src/librustc/middle/trans/cabi_mips.rs @@ -0,0 +1,221 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::{ptr, vec, uint}; +use core::option::*; +use core::libc::c_uint; +use lib::llvm::{llvm, TypeRef, ValueRef, Integer, Pointer, Float, Double}; +use lib::llvm::{Struct, Array, Attribute}; +use lib::llvm::{StructRetAttribute, ByValAttribute}; +use middle::trans::common::*; +use middle::trans::cabi::*; + +fn align_up_to(off: uint, a: uint) -> uint { + return (off + a - 1u) / a * a; +} + +fn align(off: uint, ty: TypeRef) -> uint { + let a = ty_align(ty); + return align_up_to(off, a); +} + +fn struct_tys(ty: TypeRef) -> ~[TypeRef] { + unsafe { + let n = llvm::LLVMCountStructElementTypes(ty); + if (n == 0) { + return ~[]; + } + let mut elts = vec::from_elem(n as uint, ptr::null()); + llvm::LLVMGetStructElementTypes(ty, + ptr::to_mut_unsafe_ptr(&mut elts[0])); + return elts; + } +} + +fn ty_align(ty: TypeRef) -> uint { + unsafe { + return match llvm::LLVMGetTypeKind(ty) { + Integer => { + ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 + } + Pointer => 4, + Float => 4, + Double => 8, + Struct => { + do vec::foldl(1, struct_tys(ty)) |a, t| { + uint::max(a, ty_align(*t)) + } + } + Array => { + let elt = llvm::LLVMGetElementType(ty); + ty_align(elt) + } + _ => fail!(~"ty_size: unhandled type") + }; + } +} + +fn ty_size(ty: TypeRef) -> uint { + unsafe { + return match llvm::LLVMGetTypeKind(ty) { + Integer => { + ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 + } + Pointer => 4, + Float => 4, + Double => 8, + Struct => { + let size = do vec::foldl(0, struct_tys(ty)) |s, t| { + align(s, *t) + ty_size(*t) + }; + align(size, ty) + } + Array => { + let len = llvm::LLVMGetArrayLength(ty) as uint; + let elt = llvm::LLVMGetElementType(ty); + let eltsz = ty_size(elt); + len * eltsz + } + _ => fail!(~"ty_size: unhandled type") + }; + } +} + +fn classify_ret_ty(ty: TypeRef) -> (LLVMType, Option<Attribute>) { + return if is_reg_ty(ty) { + (LLVMType { cast: false, ty: ty }, None) + } else { + (LLVMType { cast: false, ty: T_ptr(ty) }, Some(StructRetAttribute)) + }; +} + +fn classify_arg_ty(ty: TypeRef, + offset: &mut uint) -> (LLVMType, Option<Attribute>) { + let orig_offset = *offset; + let size = ty_size(ty) * 8; + let mut align = ty_align(ty); + + align = uint::min(uint::max(align, 4), 8); + *offset = align_up_to(*offset, align); + *offset += align_up_to(size, align * 8) / 8; + + let padding = padding_ty(align, orig_offset); + return if !is_reg_ty(ty) { + (LLVMType { + cast: true, + ty: struct_ty(ty, padding, true) + }, None) + } else if padding.is_some() { + (LLVMType { + cast: true, + ty: struct_ty(ty, padding, false) + }, None) + } else { + (LLVMType { cast: false, ty: ty }, None) + }; +} + +fn is_reg_ty(ty: TypeRef) -> bool { + unsafe { + return match llvm::LLVMGetTypeKind(ty) { + Integer + | Pointer + | Float + | Double => true, + _ => false + }; + } +} + +fn padding_ty(align: uint, offset: uint) -> Option<TypeRef> { + if ((align - 1 ) & offset) > 0 { + return Some(T_i32()); + } + + return None; +} + +fn coerce_to_int(size: uint) -> ~[TypeRef] { + let int_ty = T_i32(); + let mut args = ~[]; + + let mut n = size / 32; + while n > 0 { + args.push(int_ty); + n -= 1; + } + + let r = size % 32; + if r > 0 { + unsafe { + args.push(llvm::LLVMIntType(r as c_uint)) + } + } + + return args; +} + +fn struct_ty(ty: TypeRef, + padding: Option<TypeRef>, + coerce: bool) -> TypeRef { + let size = ty_size(ty) * 8; + let mut fields = padding.map_default(~[], |p| ~[*p]); + + if coerce { + fields = vec::append(fields, coerce_to_int(size)); + } else { + fields.push(ty); + } + + return T_struct(fields); +} + +enum MIPS_ABIInfo { MIPS_ABIInfo } + +impl ABIInfo for MIPS_ABIInfo { + fn compute_info(&self, + atys: &[TypeRef], + rty: TypeRef, + ret_def: bool) -> FnType { + let mut (ret_ty, ret_attr) = if ret_def { + classify_ret_ty(rty) + } else { + (LLVMType { cast: false, ty: T_void() }, None) + }; + + let sret = ret_attr.is_some(); + let mut arg_tys = ~[]; + let mut attrs = ~[]; + let mut offset = if sret { 4 } else { 0 }; + + for atys.each() |aty| { + let (ty, attr) = classify_arg_ty(*aty, &mut offset); + arg_tys.push(ty); + attrs.push(attr); + }; + + if sret { + arg_tys = vec::append(~[ret_ty], arg_tys); + attrs = vec::append(~[ret_attr], attrs); + ret_ty = LLVMType { cast: false, ty: T_void() }; + } + + return FnType { + arg_tys: arg_tys, + ret_ty: ret_ty, + attrs: attrs, + sret: sret + }; + } +} + +pub fn mips_abi_info() -> @ABIInfo { + return @MIPS_ABIInfo as @ABIInfo; +} diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 6c0c73dd016..12271f51b35 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -14,6 +14,7 @@ use back::{link, abi}; use driver::session; use driver::session::arch_x86_64; use driver::session::arch_arm; +use driver::session::arch_mips; use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg}; use lib::llvm::{Struct, Array, ModuleRef, CallConv, Attribute}; use lib::llvm::{StructRetAttribute, ByValAttribute}; @@ -23,6 +24,7 @@ use middle::trans::base::*; use middle::trans::cabi; use middle::trans::cabi_x86_64::*; use middle::trans::cabi_arm; +use middle::trans::cabi_mips::*; use middle::trans::build::*; use middle::trans::callee::*; use middle::trans::common::*; @@ -48,6 +50,7 @@ fn abi_info(arch: session::arch) -> cabi::ABIInfo { return match arch { arch_x86_64 => x86_64_abi_info(), arch_arm => cabi_arm::abi_info(), + arch_mips => mips_abi_info(), _ => cabi::llvm_abi_info() } } diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 59811468f70..8dbc0f12a88 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -70,6 +70,7 @@ pub mod middle { pub mod cabi; pub mod cabi_x86_64; pub mod cabi_arm; + pub mod cabi_mips; pub mod foreign; pub mod reflect; pub mod shape; |
