2013-04-10 07:47:22 -05:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2013-01-29 11:31:50 -06:00
|
|
|
// 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.
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::libc::c_uint;
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 11:05:17 -05:00
|
|
|
use std::num;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::vec;
|
2013-06-15 09:29:52 -05:00
|
|
|
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
|
|
|
|
use lib::llvm::{Attribute, StructRetAttribute};
|
2013-06-14 00:38:17 -05:00
|
|
|
use middle::trans::context::task_llcx;
|
2013-01-29 11:31:50 -06:00
|
|
|
use middle::trans::cabi::*;
|
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
use middle::trans::type_::Type;
|
|
|
|
|
2013-01-29 11:31:50 -06:00
|
|
|
fn align_up_to(off: uint, a: uint) -> uint {
|
|
|
|
return (off + a - 1u) / a * a;
|
|
|
|
}
|
|
|
|
|
2013-06-15 09:29:52 -05:00
|
|
|
fn align(off: uint, ty: Type) -> uint {
|
2013-01-29 11:31:50 -06:00
|
|
|
let a = ty_align(ty);
|
|
|
|
return align_up_to(off, a);
|
|
|
|
}
|
|
|
|
|
2013-06-15 22:45:48 -05:00
|
|
|
fn ty_align(ty: Type) -> uint {
|
2013-06-16 05:52:44 -05:00
|
|
|
match ty.kind() {
|
|
|
|
Integer => {
|
|
|
|
unsafe {
|
|
|
|
((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
2013-06-16 05:52:44 -05:00
|
|
|
}
|
|
|
|
Pointer => 4,
|
|
|
|
Float => 4,
|
|
|
|
Double => 8,
|
|
|
|
Struct => {
|
|
|
|
if ty.is_packed() {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
let str_tys = ty.field_types();
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 11:05:17 -05:00
|
|
|
str_tys.iter().fold(1, |a, t| num::max(a, ty_align(*t)))
|
2013-06-16 05:52:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Array => {
|
|
|
|
let elt = ty.element_type();
|
|
|
|
ty_align(elt)
|
|
|
|
}
|
|
|
|
_ => fail!("ty_size: unhandled type")
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
fn ty_size(ty: Type) -> uint {
|
|
|
|
match ty.kind() {
|
|
|
|
Integer => {
|
|
|
|
unsafe {
|
|
|
|
((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
2013-06-16 05:52:44 -05:00
|
|
|
}
|
|
|
|
Pointer => 4,
|
|
|
|
Float => 4,
|
|
|
|
Double => 8,
|
|
|
|
Struct => {
|
|
|
|
if ty.is_packed() {
|
|
|
|
let str_tys = ty.field_types();
|
|
|
|
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
|
|
|
|
} else {
|
|
|
|
let str_tys = ty.field_types();
|
|
|
|
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
|
|
|
|
align(size, ty)
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
2013-06-16 05:52:44 -05:00
|
|
|
}
|
|
|
|
Array => {
|
|
|
|
let len = ty.array_length();
|
|
|
|
let elt = ty.element_type();
|
|
|
|
let eltsz = ty_size(elt);
|
|
|
|
len * eltsz
|
|
|
|
}
|
|
|
|
_ => fail!("ty_size: unhandled type")
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-15 22:45:48 -05:00
|
|
|
fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
|
2013-01-29 11:31:50 -06:00
|
|
|
return if is_reg_ty(ty) {
|
|
|
|
(LLVMType { cast: false, ty: ty }, None)
|
|
|
|
} else {
|
2013-06-15 22:45:48 -05:00
|
|
|
(LLVMType { cast: false, ty: ty.ptr_to() }, Some(StructRetAttribute))
|
2013-01-29 11:31:50 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-06-15 22:45:48 -05:00
|
|
|
fn classify_arg_ty(ty: Type, offset: &mut uint) -> (LLVMType, Option<Attribute>) {
|
2013-01-29 11:31:50 -06:00
|
|
|
let orig_offset = *offset;
|
|
|
|
let size = ty_size(ty) * 8;
|
|
|
|
let mut align = ty_align(ty);
|
|
|
|
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 11:05:17 -05:00
|
|
|
align = num::min(num::max(align, 4), 8);
|
2013-01-29 11:31:50 -06:00
|
|
|
*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)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
fn is_reg_ty(ty: Type) -> bool {
|
2013-06-16 06:11:17 -05:00
|
|
|
return match ty.kind() {
|
|
|
|
Integer
|
|
|
|
| Pointer
|
|
|
|
| Float
|
|
|
|
| Double => true,
|
|
|
|
_ => false
|
|
|
|
};
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
|
2013-06-15 22:45:48 -05:00
|
|
|
fn padding_ty(align: uint, offset: uint) -> Option<Type> {
|
2013-01-29 11:31:50 -06:00
|
|
|
if ((align - 1 ) & offset) > 0 {
|
2013-06-15 22:45:48 -05:00
|
|
|
return Some(Type::i32());
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2013-06-15 22:45:48 -05:00
|
|
|
fn coerce_to_int(size: uint) -> ~[Type] {
|
|
|
|
let int_ty = Type::i32();
|
2013-01-29 11:31:50 -06:00
|
|
|
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 {
|
2013-06-16 05:52:44 -05:00
|
|
|
args.push(Type::from_ref(llvm::LLVMIntTypeInContext(task_llcx(), r as c_uint)));
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
args
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
|
2013-06-15 22:45:48 -05:00
|
|
|
fn struct_ty(ty: Type,
|
|
|
|
padding: Option<Type>,
|
|
|
|
coerce: bool) -> Type {
|
2013-01-29 11:31:50 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-06-15 22:45:48 -05:00
|
|
|
return Type::struct_(fields, false);
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
enum MIPS_ABIInfo { MIPS_ABIInfo }
|
|
|
|
|
|
|
|
impl ABIInfo for MIPS_ABIInfo {
|
|
|
|
fn compute_info(&self,
|
2013-06-15 22:45:48 -05:00
|
|
|
atys: &[Type],
|
|
|
|
rty: Type,
|
2013-01-29 11:31:50 -06:00
|
|
|
ret_def: bool) -> FnType {
|
2013-06-06 20:54:14 -05:00
|
|
|
let (ret_ty, ret_attr) = if ret_def {
|
2013-01-29 11:31:50 -06:00
|
|
|
classify_ret_ty(rty)
|
|
|
|
} else {
|
2013-06-15 22:45:48 -05:00
|
|
|
(LLVMType { cast: false, ty: Type::void() }, None)
|
2013-01-29 11:31:50 -06:00
|
|
|
};
|
|
|
|
|
2013-06-06 20:54:14 -05:00
|
|
|
let mut ret_ty = ret_ty;
|
|
|
|
|
2013-01-29 11:31:50 -06:00
|
|
|
let sret = ret_attr.is_some();
|
|
|
|
let mut arg_tys = ~[];
|
|
|
|
let mut attrs = ~[];
|
|
|
|
let mut offset = if sret { 4 } else { 0 };
|
|
|
|
|
2013-08-03 11:45:23 -05:00
|
|
|
for aty in atys.iter() {
|
2013-01-29 11:31:50 -06:00
|
|
|
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);
|
2013-06-15 22:45:48 -05:00
|
|
|
ret_ty = LLVMType { cast: false, ty: Type::void() };
|
2013-01-29 11:31:50 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return FnType {
|
|
|
|
arg_tys: arg_tys,
|
|
|
|
ret_ty: ret_ty,
|
|
|
|
attrs: attrs,
|
|
|
|
sret: sret
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-01 19:47:38 -05:00
|
|
|
pub fn abi_info() -> @ABIInfo {
|
2013-01-29 11:31:50 -06:00
|
|
|
return @MIPS_ABIInfo as @ABIInfo;
|
|
|
|
}
|