]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/cabi.rs
b7e157bc7e25423fdc442a6c4ecaff064002cbe3
[rust.git] / src / librustc / middle / trans / cabi.rs
1 // Copyright 2012 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 lib::llvm::{llvm, ValueRef, Attribute, Void};
12 use middle::trans::base::*;
13 use middle::trans::build::*;
14 use middle::trans::common::*;
15
16 use middle::trans::type_::Type;
17
18 use std::libc::c_uint;
19 use std::option;
20
21 pub trait ABIInfo {
22     fn compute_info(&self, atys: &[Type], rty: Type, ret_def: bool) -> FnType;
23 }
24
25 #[deriving(Clone)]
26 pub struct LLVMType {
27     cast: bool,
28     ty: Type
29 }
30
31 pub struct FnType {
32     arg_tys: ~[LLVMType],
33     ret_ty: LLVMType,
34     attrs: ~[option::Option<Attribute>],
35     sret: bool
36 }
37
38 impl FnType {
39     pub fn decl_fn(&self, decl: &fn(fnty: Type) -> ValueRef) -> ValueRef {
40         let atys = self.arg_tys.iter().transform(|t| t.ty).collect::<~[Type]>();
41         let rty = self.ret_ty.ty;
42         let fnty = Type::func(atys, &rty);
43         let llfn = decl(fnty);
44
45         for self.attrs.iter().enumerate().advance |(i, a)| {
46             match *a {
47                 option::Some(attr) => {
48                     unsafe {
49                         let llarg = get_param(llfn, i);
50                         llvm::LLVMAddAttribute(llarg, attr as c_uint);
51                     }
52                 }
53                 _ => ()
54             }
55         }
56         return llfn;
57     }
58
59     pub fn build_shim_args(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef)
60                            -> ~[ValueRef] {
61         let mut atys: &[LLVMType] = self.arg_tys;
62         let mut attrs: &[option::Option<Attribute>] = self.attrs;
63
64         let mut llargvals = ~[];
65         let mut i = 0u;
66         let n = arg_tys.len();
67
68         if self.sret {
69             let llretptr = GEPi(bcx, llargbundle, [0u, n]);
70             let llretloc = Load(bcx, llretptr);
71                 llargvals = ~[llretloc];
72                 atys = atys.tail();
73                 attrs = attrs.tail();
74         }
75
76         while i < n {
77             let llargval = if atys[i].cast {
78                 let arg_ptr = GEPi(bcx, llargbundle, [0u, i]);
79                 let arg_ptr = BitCast(bcx, arg_ptr, atys[i].ty.ptr_to());
80                 Load(bcx, arg_ptr)
81             } else if attrs[i].is_some() {
82                 GEPi(bcx, llargbundle, [0u, i])
83             } else {
84                 load_inbounds(bcx, llargbundle, [0u, i])
85             };
86             llargvals.push(llargval);
87             i += 1u;
88         }
89
90         return llargvals;
91     }
92
93     pub fn build_shim_ret(&self, bcx: block, arg_tys: &[Type], ret_def: bool,
94                           llargbundle: ValueRef, llretval: ValueRef) {
95         for self.attrs.iter().enumerate().advance |(i, a)| {
96             match *a {
97                 option::Some(attr) => {
98                     unsafe {
99                         llvm::LLVMAddInstrAttribute(llretval, (i + 1u) as c_uint, attr as c_uint);
100                     }
101                 }
102                 _ => ()
103             }
104         }
105         if self.sret || !ret_def {
106             return;
107         }
108         let n = arg_tys.len();
109         // R** llretptr = &args->r;
110         let llretptr = GEPi(bcx, llargbundle, [0u, n]);
111         // R* llretloc = *llretptr; /* (args->r) */
112         let llretloc = Load(bcx, llretptr);
113         if self.ret_ty.cast {
114             let tmp_ptr = BitCast(bcx, llretloc, self.ret_ty.ty.ptr_to());
115             // *args->r = r;
116             Store(bcx, llretval, tmp_ptr);
117         } else {
118             // *args->r = r;
119             Store(bcx, llretval, llretloc);
120         };
121     }
122
123     pub fn build_wrap_args(&self, bcx: block, ret_ty: Type,
124                            llwrapfn: ValueRef, llargbundle: ValueRef) {
125         let mut atys: &[LLVMType] = self.arg_tys;
126         let mut attrs: &[option::Option<Attribute>] = self.attrs;
127         let mut j = 0u;
128         let llretptr = if self.sret {
129             atys = atys.tail();
130             attrs = attrs.tail();
131             j = 1u;
132             get_param(llwrapfn, 0u)
133         } else if self.ret_ty.cast {
134             let retptr = alloca(bcx, self.ret_ty.ty, "");
135             BitCast(bcx, retptr, ret_ty.ptr_to())
136         } else {
137             alloca(bcx, ret_ty, "")
138         };
139
140         let mut i = 0u;
141         let n = atys.len();
142         while i < n {
143             let mut argval = get_param(llwrapfn, i + j);
144             if attrs[i].is_some() {
145                 argval = Load(bcx, argval);
146                 store_inbounds(bcx, argval, llargbundle, [0u, i]);
147             } else if atys[i].cast {
148                 let argptr = GEPi(bcx, llargbundle, [0u, i]);
149                 let argptr = BitCast(bcx, argptr, atys[i].ty.ptr_to());
150                 Store(bcx, argval, argptr);
151             } else {
152                 store_inbounds(bcx, argval, llargbundle, [0u, i]);
153             }
154             i += 1u;
155         }
156         store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
157     }
158
159     pub fn build_wrap_ret(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef) {
160         if self.ret_ty.ty.kind() == Void {
161             return;
162         }
163
164         if bcx.fcx.llretptr.is_some() {
165             let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]);
166             let llretval = if self.ret_ty.cast {
167                 let retptr = BitCast(bcx, llretval, self.ret_ty.ty.ptr_to());
168                 Load(bcx, retptr)
169             } else {
170                 Load(bcx, llretval)
171             };
172             let llretptr = BitCast(bcx, bcx.fcx.llretptr.get(), self.ret_ty.ty.ptr_to());
173             Store(bcx, llretval, llretptr);
174         }
175     }
176 }