1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(non_uppercase_pattern_statics)]
12
13 use libc::c_uint;
14 use std::cmp;
15 use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
16 use lib::llvm::StructRetAttribute;
17 use middle::trans::context::CrateContext;
18 use middle::trans::cabi::*;
19 use middle::trans::type_::Type;
20
21 fn align_up_to(off: uint, a: uint) -> uint {
22 return (off + a - 1u) / a * a;
23 }
24
25 fn align(off: uint, ty: Type) -> uint {
26 let a = ty_align(ty);
27 return align_up_to(off, a);
28 }
29
30 fn ty_align(ty: Type) -> uint {
31 match ty.kind() {
32 Integer => {
33 unsafe {
34 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
35 }
36 }
37 Pointer => 4,
38 Float => 4,
39 Double => 8,
40 Struct => {
41 if ty.is_packed() {
42 1
43 } else {
44 let str_tys = ty.field_types();
45 str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
46 }
47 }
48 Array => {
49 let elt = ty.element_type();
50 ty_align(elt)
51 }
52 _ => fail!("ty_size: unhandled type")
53 }
54 }
55
56 fn ty_size(ty: Type) -> uint {
57 match ty.kind() {
58 Integer => {
59 unsafe {
60 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
61 }
62 }
63 Pointer => 4,
64 Float => 4,
65 Double => 8,
66 Struct => {
67 if ty.is_packed() {
68 let str_tys = ty.field_types();
69 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
70 } else {
71 let str_tys = ty.field_types();
72 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
73 align(size, ty)
74 }
75 }
76 Array => {
77 let len = ty.array_length();
78 let elt = ty.element_type();
79 let eltsz = ty_size(elt);
80 len * eltsz
81 }
82 _ => fail!("ty_size: unhandled type")
83 }
84 }
85
86 fn classify_ret_ty(ty: Type) -> ArgType {
87 if is_reg_ty(ty) {
88 ArgType::direct(ty, None, None, None)
89 } else {
90 ArgType::indirect(ty, Some(StructRetAttribute))
91 }
92 }
93
94 fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut uint) -> ArgType {
95 let orig_offset = *offset;
96 let size = ty_size(ty) * 8;
97 let mut align = ty_align(ty);
98
99 align = cmp::min(cmp::max(align, 4), 8);
100 *offset = align_up_to(*offset, align);
101 *offset += align_up_to(size, align * 8) / 8;
102
103 if is_reg_ty(ty) {
104 ArgType::direct(ty, None, None, None)
105 } else {
106 ArgType::direct(
107 ty,
108 Some(struct_ty(ccx, ty)),
109 padding_ty(ccx, align, orig_offset),
110 None
111 )
112 }
113 }
114
115 fn is_reg_ty(ty: Type) -> bool {
116 return match ty.kind() {
117 Integer
118 | Pointer
119 | Float
120 | Double => true,
121 _ => false
122 };
123 }
124
125 fn padding_ty(ccx: &CrateContext, align: uint, offset: uint) -> Option<Type> {
126 if ((align - 1 ) & offset) > 0 {
127 Some(Type::i32(ccx))
128 } else {
129 None
130 }
131 }
132
133 fn coerce_to_int(ccx: &CrateContext, size: uint) -> Vec<Type> {
134 let int_ty = Type::i32(ccx);
135 let mut args = Vec::new();
136
137 let mut n = size / 32;
138 while n > 0 {
139 args.push(int_ty);
140 n -= 1;
141 }
142
143 let r = size % 32;
144 if r > 0 {
145 unsafe {
146 args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx, r as c_uint)));
147 }
148 }
149
150 args
151 }
152
153 fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
154 let size = ty_size(ty) * 8;
155 Type::struct_(ccx, coerce_to_int(ccx, size).as_slice(), false)
156 }
157
158 pub fn compute_abi_info(ccx: &CrateContext,
159 atys: &[Type],
160 rty: Type,
161 ret_def: bool) -> FnType {
162 let ret_ty = if ret_def {
163 classify_ret_ty(rty)
164 } else {
165 ArgType::direct(Type::void(ccx), None, None, None)
166 };
167
168 let sret = ret_ty.is_indirect();
169 let mut arg_tys = Vec::new();
170 let mut offset = if sret { 4 } else { 0 };
171
172 for aty in atys.iter() {
173 let ty = classify_arg_ty(ccx, *aty, &mut offset);
174 arg_tys.push(ty);
175 };
176
177 return FnType {
178 arg_tys: arg_tys,
179 ret_ty: ret_ty,
180 };
181 }
librustc/middle/trans/cabi_mips.rs:20:1-20:1 -fn- definition:
fn align_up_to(off: uint, a: uint) -> uint {
return (off + a - 1u) / a * a;
}
references:- 326: let a = ty_align(ty);
27: return align_up_to(off, a);
28: }
--
99: align = cmp::min(cmp::max(align, 4), 8);
100: *offset = align_up_to(*offset, align);
101: *offset += align_up_to(size, align * 8) / 8;
librustc/middle/trans/cabi_mips.rs:24:1-24:1 -fn- definition:
fn align(off: uint, ty: Type) -> uint {
let a = ty_align(ty);
return align_up_to(off, a);
references:- 271: let str_tys = ty.field_types();
72: let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
73: align(size, ty)
74: }
librustc/middle/trans/cabi_mips.rs:29:1-29:1 -fn- definition:
fn ty_align(ty: Type) -> uint {
match ty.kind() {
Integer => {
references:- 425: fn align(off: uint, ty: Type) -> uint {
26: let a = ty_align(ty);
27: return align_up_to(off, a);
--
44: let str_tys = ty.field_types();
45: str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
46: }
--
49: let elt = ty.element_type();
50: ty_align(elt)
51: }
--
96: let size = ty_size(ty) * 8;
97: let mut align = ty_align(ty);
librustc/middle/trans/cabi_mips.rs:55:1-55:1 -fn- definition:
fn ty_size(ty: Type) -> uint {
match ty.kind() {
Integer => {
references:- 5153: fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
154: let size = ty_size(ty) * 8;
155: Type::struct_(ccx, coerce_to_int(ccx, size).as_slice(), false)
librustc/middle/trans/cabi_mips.rs:114:1-114:1 -fn- definition:
fn is_reg_ty(ty: Type) -> bool {
return match ty.kind() {
Integer
references:- 2103: if is_reg_ty(ty) {
104: ArgType::direct(ty, None, None, None)