]> git.lizzy.rs Git - rust.git/commitdiff
rustc: implement MIPS O32 ABI
authorJyun-Yan You <jyyou@cs.nctu.edu.tw>
Tue, 29 Jan 2013 17:31:50 +0000 (01:31 +0800)
committerBrian Anderson <banderson@mozilla.com>
Mon, 4 Mar 2013 04:02:03 +0000 (20:02 -0800)
src/librustc/back/mips.rs
src/librustc/middle/trans/cabi_mips.rs [new file with mode: 0644]
src/librustc/middle/trans/foreign.rs
src/librustc/rustc.rc

index 32d434ed49d3b636d787a95dd286210c84650acc..93c1879eb0f4be89791c790beb42f89a9e849809 100644 (file)
@@ -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 (file)
index 0000000..4f5e9ed
--- /dev/null
@@ -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;
+}
index 6c0c73dd016f268c6f786d8a9846cb51db2c054d..12271f51b35d19db30fe5d779b7b890ade7c1691 100644 (file)
@@ -14,6 +14,7 @@
 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::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()
     }
 }
index 59811468f701207619610453736a773a5d48c31f..8dbc0f12a88cfc158cf960f8392f34ecc8123757 100644 (file)
@@ -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;