Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 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 | |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 11 | use lib::llvm::{llvm, ValueRef, Attribute, Void}; |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 12 | use middle::trans::base::*; |
| 13 | use middle::trans::build::*; |
| 14 | use middle::trans::common::*; |
| 15 | |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 16 | use middle::trans::type_::Type; |
| 17 | |
Alex Crichton | 2df07dd | 2013-02-25 19:11:21 | [diff] [blame] | 18 | use core::libc::c_uint; |
| 19 | use core::option; |
| 20 | use core::vec; |
| 21 | |
Patrick Walton | ba11e96 | 2013-01-30 19:46:19 | [diff] [blame] | 22 | pub trait ABIInfo { |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 23 | fn compute_info(&self, atys: &[Type], rty: Type, ret_def: bool) -> FnType; |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 24 | } |
| 25 | |
Patrick Walton | ba11e96 | 2013-01-30 19:46:19 | [diff] [blame] | 26 | pub struct LLVMType { |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 27 | cast: bool, |
James Miller | fd83b92 | 2013-06-15 14:29:52 | [diff] [blame] | 28 | ty: Type |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 29 | } |
| 30 | |
Patrick Walton | ba11e96 | 2013-01-30 19:46:19 | [diff] [blame] | 31 | pub struct FnType { |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 32 | arg_tys: ~[LLVMType], |
| 33 | ret_ty: LLVMType, |
Alex Crichton | 2df07dd | 2013-02-25 19:11:21 | [diff] [blame] | 34 | attrs: ~[option::Option<Attribute>], |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 35 | sret: bool |
| 36 | } |
| 37 | |
Patrick Walton | 5fb2546 | 2013-05-31 22:17:22 | [diff] [blame] | 38 | impl FnType { |
James Miller | fd83b92 | 2013-06-15 14:29:52 | [diff] [blame] | 39 | pub fn decl_fn(&self, decl: &fn(fnty: Type) -> ValueRef) -> ValueRef { |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 40 | let atys = vec::map(self.arg_tys, |t| t.ty); |
| 41 | let rty = self.ret_ty.ty; |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 42 | let fnty = Type::func(atys, &rty); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 43 | let llfn = decl(fnty); |
| 44 | |
Daniel Micay | cbad1da | 2013-06-17 20:37:11 | [diff] [blame] | 45 | for self.attrs.iter().enumerate().advance |(i, a)| { |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 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 | |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 59 | pub fn build_shim_args(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef) |
Patrick Walton | 5fb2546 | 2013-05-31 22:17:22 | [diff] [blame] | 60 | -> ~[ValueRef] { |
Björn Steinbrink | 1720d9f | 2013-05-29 18:10:16 | [diff] [blame] | 61 | let mut atys: &[LLVMType] = self.arg_tys; |
| 62 | let mut attrs: &[option::Option<Attribute>] = self.attrs; |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 63 | |
| 64 | let mut llargvals = ~[]; |
| 65 | let mut i = 0u; |
Youngmin Yoo | a2a8596 | 2013-05-14 09:52:12 | [diff] [blame] | 66 | let n = arg_tys.len(); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 67 | |
| 68 | if self.sret { |
| 69 | let llretptr = GEPi(bcx, llargbundle, [0u, n]); |
| 70 | let llretloc = Load(bcx, llretptr); |
| 71 | llargvals = ~[llretloc]; |
Björn Steinbrink | 1720d9f | 2013-05-29 18:10:16 | [diff] [blame] | 72 | atys = atys.tail(); |
| 73 | attrs = attrs.tail(); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 74 | } |
| 75 | |
| 76 | while i < n { |
| 77 | let llargval = if atys[i].cast { |
| 78 | let arg_ptr = GEPi(bcx, llargbundle, [0u, i]); |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 79 | let arg_ptr = BitCast(bcx, arg_ptr, atys[i].ty.ptr_to()); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 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 | |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 93 | pub fn build_shim_ret(&self, bcx: block, arg_tys: &[Type], ret_def: bool, |
| 94 | llargbundle: ValueRef, llretval: ValueRef) { |
Daniel Micay | cbad1da | 2013-06-17 20:37:11 | [diff] [blame] | 95 | for self.attrs.iter().enumerate().advance |(i, a)| { |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 96 | match *a { |
Alex Crichton | 2df07dd | 2013-02-25 19:11:21 | [diff] [blame] | 97 | option::Some(attr) => { |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 98 | unsafe { |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 99 | llvm::LLVMAddInstrAttribute(llretval, (i + 1u) as c_uint, attr as c_uint); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 100 | } |
| 101 | } |
| 102 | _ => () |
| 103 | } |
| 104 | } |
| 105 | if self.sret || !ret_def { |
| 106 | return; |
| 107 | } |
Youngmin Yoo | a2a8596 | 2013-05-14 09:52:12 | [diff] [blame] | 108 | let n = arg_tys.len(); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 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 { |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 114 | let tmp_ptr = BitCast(bcx, llretloc, self.ret_ty.ty.ptr_to()); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 115 | // *args->r = r; |
| 116 | Store(bcx, llretval, tmp_ptr); |
| 117 | } else { |
| 118 | // *args->r = r; |
| 119 | Store(bcx, llretval, llretloc); |
| 120 | }; |
| 121 | } |
| 122 | |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 123 | pub fn build_wrap_args(&self, bcx: block, ret_ty: Type, |
| 124 | llwrapfn: ValueRef, llargbundle: ValueRef) { |
Björn Steinbrink | 1720d9f | 2013-05-29 18:10:16 | [diff] [blame] | 125 | let mut atys: &[LLVMType] = self.arg_tys; |
| 126 | let mut attrs: &[option::Option<Attribute>] = self.attrs; |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 127 | let mut j = 0u; |
| 128 | let llretptr = if self.sret { |
Björn Steinbrink | 1720d9f | 2013-05-29 18:10:16 | [diff] [blame] | 129 | atys = atys.tail(); |
| 130 | attrs = attrs.tail(); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 131 | j = 1u; |
| 132 | get_param(llwrapfn, 0u) |
| 133 | } else if self.ret_ty.cast { |
| 134 | let retptr = alloca(bcx, self.ret_ty.ty); |
James Miller | fd83b92 | 2013-06-15 14:29:52 | [diff] [blame] | 135 | BitCast(bcx, retptr, ret_ty.ptr_to()) |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 136 | } else { |
| 137 | alloca(bcx, ret_ty) |
| 138 | }; |
| 139 | |
| 140 | let mut i = 0u; |
Youngmin Yoo | a2a8596 | 2013-05-14 09:52:12 | [diff] [blame] | 141 | let n = atys.len(); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 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]); |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 149 | let argptr = BitCast(bcx, argptr, atys[i].ty.ptr_to()); |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 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 | |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 159 | pub fn build_wrap_ret(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef) { |
| 160 | if self.ret_ty.ty.kind() == Void { |
| 161 | return; |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 162 | } |
Patrick Walton | c995a62 | 2013-04-18 22:53:29 | [diff] [blame] | 163 | |
Björn Steinbrink | 4fb2c09 | 2013-06-20 14:42:44 | [diff] [blame] | 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 { |
James Miller | fd83b92 | 2013-06-15 14:29:52 | [diff] [blame] | 167 | let retptr = BitCast(bcx, llretval, self.ret_ty.ty.ptr_to()); |
Björn Steinbrink | 4fb2c09 | 2013-06-20 14:42:44 | [diff] [blame] | 168 | Load(bcx, retptr) |
| 169 | } else { |
| 170 | Load(bcx, llretval) |
| 171 | }; |
James Miller | 81cf72c | 2013-06-16 10:52:44 | [diff] [blame] | 172 | let llretptr = BitCast(bcx, bcx.fcx.llretptr.get(), self.ret_ty.ty.ptr_to()); |
Björn Steinbrink | 4fb2c09 | 2013-06-20 14:42:44 | [diff] [blame] | 173 | Store(bcx, llretval, llretptr); |
| 174 | } |
Tim Chevalier | 41adf9d | 2013-01-25 22:56:56 | [diff] [blame] | 175 | } |
| 176 | } |