]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/cabi_powerpc.rs
Merge VariantData and VariantData_
[rust.git] / src / librustc_trans / trans / cabi_powerpc.rs
1 // Copyright 2014-2015 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 use libc::c_uint;
12 use llvm;
13 use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
14 use trans::cabi::{FnType, ArgType};
15 use trans::context::CrateContext;
16 use trans::type_::Type;
17
18 use std::cmp;
19
20 fn align_up_to(off: usize, a: usize) -> usize {
21     return (off + a - 1) / a * a;
22 }
23
24 fn align(off: usize, ty: Type) -> usize {
25     let a = ty_align(ty);
26     return align_up_to(off, a);
27 }
28
29 fn ty_align(ty: Type) -> usize {
30     match ty.kind() {
31         Integer => {
32             unsafe {
33                 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8
34             }
35         }
36         Pointer => 4,
37         Float => 4,
38         Double => 8,
39         Struct => {
40           if ty.is_packed() {
41             1
42           } else {
43             let str_tys = ty.field_types();
44             str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
45           }
46         }
47         Array => {
48             let elt = ty.element_type();
49             ty_align(elt)
50         }
51         _ => panic!("ty_size: unhandled type")
52     }
53 }
54
55 fn ty_size(ty: Type) -> usize {
56     match ty.kind() {
57         Integer => {
58             unsafe {
59                 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8
60             }
61         }
62         Pointer => 4,
63         Float => 4,
64         Double => 8,
65         Struct => {
66             if ty.is_packed() {
67                 let str_tys = ty.field_types();
68                 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
69             } else {
70                 let str_tys = ty.field_types();
71                 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
72                 align(size, ty)
73             }
74         }
75         Array => {
76             let len = ty.array_length();
77             let elt = ty.element_type();
78             let eltsz = ty_size(elt);
79             len * eltsz
80         }
81         _ => panic!("ty_size: unhandled type")
82     }
83 }
84
85 fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
86     if is_reg_ty(ty) {
87         let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
88         ArgType::direct(ty, None, None, attr)
89     } else {
90         ArgType::indirect(ty, Some(Attribute::StructRet))
91     }
92 }
93
94 fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut usize) -> 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         let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
105         ArgType::direct(ty, None, None, attr)
106     } else {
107         ArgType::direct(
108             ty,
109             Some(struct_ty(ccx, ty)),
110             padding_ty(ccx, align, orig_offset),
111             None
112         )
113     }
114 }
115
116 fn is_reg_ty(ty: Type) -> bool {
117     return match ty.kind() {
118         Integer
119         | Pointer
120         | Float
121         | Double => true,
122         _ => false
123     };
124 }
125
126 fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
127     if ((align - 1 ) & offset) > 0 {
128         Some(Type::i32(ccx))
129     } else {
130         None
131     }
132 }
133
134 fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
135     let int_ty = Type::i32(ccx);
136     let mut args = Vec::new();
137
138     let mut n = size / 32;
139     while n > 0 {
140         args.push(int_ty);
141         n -= 1;
142     }
143
144     let r = size % 32;
145     if r > 0 {
146         unsafe {
147             args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
148         }
149     }
150
151     args
152 }
153
154 fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
155     let size = ty_size(ty) * 8;
156     Type::struct_(ccx, &coerce_to_int(ccx, size), false)
157 }
158
159 pub fn compute_abi_info(ccx: &CrateContext,
160                         atys: &[Type],
161                         rty: Type,
162                         ret_def: bool) -> FnType {
163     let ret_ty = if ret_def {
164         classify_ret_ty(ccx, rty)
165     } else {
166         ArgType::direct(Type::void(ccx), None, None, None)
167     };
168
169     let sret = ret_ty.is_indirect();
170     let mut arg_tys = Vec::new();
171     let mut offset = if sret { 4 } else { 0 };
172
173     for aty in atys {
174         let ty = classify_arg_ty(ccx, *aty, &mut offset);
175         arg_tys.push(ty);
176     };
177
178     return FnType {
179         arg_tys: arg_tys,
180         ret_ty: ret_ty,
181     };
182 }