about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-02-26 17:57:41 -0800
committerbors <bors@rust-lang.org>2013-02-26 17:57:41 -0800
commit93a7f237d78bf84494ed158a43e4aeae9966dd7c (patch)
tree1937cae3b8037078b465ac9538555b00efce2151
parenta8f07dc9df24af3cf06171bfde1a68b3058e2ec5 (diff)
parent5098cf5bd2abbef4418e93c9ab7db1eac43bb1bb (diff)
downloadrust-93a7f237d78bf84494ed158a43e4aeae9966dd7c.tar.gz
rust-93a7f237d78bf84494ed158a43e4aeae9966dd7c.zip
auto merge of #5115 : sanxiyn/rust/arm-abi, r=brson
Type size and alignment code needs to be factored, but I didn't want to interfere with MIPS port. Can be done later.

Fix #4797.
-rw-r--r--src/librustc/middle/trans/cabi_arm.rs164
-rw-r--r--src/librustc/middle/trans/foreign.rs4
-rw-r--r--src/librustc/rustc.rc1
3 files changed, 168 insertions, 1 deletions
diff --git a/src/librustc/middle/trans/cabi_arm.rs b/src/librustc/middle/trans/cabi_arm.rs
new file mode 100644
index 00000000000..259392bef40
--- /dev/null
+++ b/src/librustc/middle/trans/cabi_arm.rs
@@ -0,0 +1,164 @@
+// Copyright 2012-2013 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 lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
+use lib::llvm::struct_tys;
+use lib::llvm::TypeRef;
+use lib::llvm::{Attribute, StructRetAttribute};
+use middle::trans::cabi::{ABIInfo, FnType, LLVMType};
+use middle::trans::common::{T_i8, T_i16, T_i32, T_i64};
+use middle::trans::common::{T_array, T_ptr, T_void};
+
+use core::option::{Option, None, Some};
+use core::uint;
+use core::vec;
+
+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 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_align: 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>) {
+    if is_reg_ty(ty) {
+        return (LLVMType { cast: false, ty: ty }, None);
+    }
+    let size = ty_size(ty);
+    if size <= 4 {
+        let llty = if size <= 1 {
+            T_i8()
+        } else if size <= 2 {
+            T_i16()
+        } else {
+            T_i32()
+        };
+        return (LLVMType { cast: true, ty: llty }, None);
+    }
+    (LLVMType { cast: false, ty: T_ptr(ty) }, Some(StructRetAttribute))
+}
+
+fn classify_arg_ty(ty: TypeRef) -> (LLVMType, Option<Attribute>) {
+    if is_reg_ty(ty) {
+        return (LLVMType { cast: false, ty: ty }, None);
+    }
+    let align = ty_align(ty);
+    let size = ty_size(ty);
+    let llty = if align <= 4 {
+        T_array(T_i32(), (size + 3) / 4)
+    } else {
+        T_array(T_i64(), (size + 7) / 8)
+    };
+    (LLVMType { cast: true, ty: llty }, None)
+}
+
+fn is_reg_ty(ty: TypeRef) -> bool {
+    unsafe {
+        return match llvm::LLVMGetTypeKind(ty) {
+            Integer
+            | Pointer
+            | Float
+            | Double => true,
+            _ => false
+        };
+    }
+}
+
+enum ARM_ABIInfo { ARM_ABIInfo }
+
+impl ABIInfo for ARM_ABIInfo {
+    fn compute_info(&self,
+                    atys: &[TypeRef],
+                    rty: TypeRef,
+                    ret_def: bool) -> FnType {
+        let mut arg_tys = ~[];
+        let mut attrs = ~[];
+        for atys.each |&aty| {
+            let (ty, attr) = classify_arg_ty(aty);
+            arg_tys.push(ty);
+            attrs.push(attr);
+        }
+
+        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();
+        if sret {
+            arg_tys.unshift(ret_ty);
+            attrs.unshift(ret_attr);
+            ret_ty = LLVMType { cast: false, ty: T_void() };
+        }
+
+        return FnType {
+            arg_tys: arg_tys,
+            ret_ty: ret_ty,
+            attrs: attrs,
+            sret: sret
+        };
+    }
+}
+
+pub fn abi_info() -> ABIInfo {
+    return ARM_ABIInfo as ABIInfo;
+}
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 3d1d70abefd..ef9cc89eb90 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -21,6 +21,7 @@ use lib;
 use middle::trans::base::*;
 use middle::trans::cabi;
 use middle::trans::cabi_x86_64::*;
+use middle::trans::cabi_arm;
 use middle::trans::build::*;
 use middle::trans::callee::*;
 use middle::trans::common::*;
@@ -42,7 +43,8 @@ use syntax::parse::token::special_idents;
 
 fn abi_info(arch: session::arch) -> cabi::ABIInfo {
     return match arch {
-        arch_x86_64 | arch_arm => x86_64_abi_info(),
+        arch_x86_64 => x86_64_abi_info(),
+        arch_arm => cabi_arm::abi_info(),
         _ => cabi::llvm_abi_info()
     }
 }
diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc
index 251e21578a5..f6fe4a04b3a 100644
--- a/src/librustc/rustc.rc
+++ b/src/librustc/rustc.rc
@@ -68,6 +68,7 @@ pub mod middle {
         pub mod meth;
         pub mod cabi;
         pub mod cabi_x86_64;
+        pub mod cabi_arm;
         pub mod foreign;
         pub mod reflect;
         pub mod shape;