]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::builder::Builder; |
2 | use crate::context::CodegenCx; | |
60c5eb7d | 3 | use crate::llvm::{self, AttributePlace}; |
9fa01778 | 4 | use crate::type_::Type; |
60c5eb7d | 5 | use crate::type_of::LayoutLlvmExt; |
9fa01778 | 6 | use crate::value::Value; |
60c5eb7d | 7 | |
dfeec247 XL |
8 | use rustc_codegen_ssa::mir::operand::OperandValue; |
9 | use rustc_codegen_ssa::mir::place::PlaceRef; | |
a1dfa0c6 | 10 | use rustc_codegen_ssa::traits::*; |
dfeec247 | 11 | use rustc_codegen_ssa::MemFlags; |
ba9703b0 XL |
12 | use rustc_middle::bug; |
13 | pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; | |
14 | use rustc_middle::ty::Ty; | |
60c5eb7d | 15 | use rustc_target::abi::call::ArgAbi; |
83c7162d | 16 | pub use rustc_target::abi::call::*; |
ba9703b0 | 17 | use rustc_target::abi::{self, HasDataLayout, Int, LayoutOf}; |
dfeec247 | 18 | pub use rustc_target::spec::abi::Abi; |
476ff2be | 19 | |
ba9703b0 XL |
20 | use libc::c_uint; |
21 | ||
476ff2be SL |
22 | macro_rules! for_each_kind { |
23 | ($flags: ident, $f: ident, $($kind: ident),+) => ({ | |
24 | $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+ | |
25 | }) | |
26 | } | |
27 | ||
83c7162d | 28 | trait ArgAttributeExt { |
dfeec247 XL |
29 | fn for_each_kind<F>(&self, f: F) |
30 | where | |
31 | F: FnMut(llvm::Attribute); | |
83c7162d XL |
32 | } |
33 | ||
34 | impl ArgAttributeExt for ArgAttribute { | |
dfeec247 XL |
35 | fn for_each_kind<F>(&self, mut f: F) |
36 | where | |
37 | F: FnMut(llvm::Attribute), | |
38 | { | |
39 | for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg) | |
476ff2be SL |
40 | } |
41 | } | |
42 | ||
83c7162d | 43 | pub trait ArgAttributesExt { |
416331ca XL |
44 | fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>); |
45 | fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>); | |
476ff2be SL |
46 | } |
47 | ||
83c7162d | 48 | impl ArgAttributesExt for ArgAttributes { |
416331ca | 49 | fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) { |
ff7c6d11 | 50 | let mut regular = self.regular; |
476ff2be | 51 | unsafe { |
ff7c6d11 XL |
52 | let deref = self.pointee_size.bytes(); |
53 | if deref != 0 { | |
54 | if regular.contains(ArgAttribute::NonNull) { | |
dfeec247 | 55 | llvm::LLVMRustAddDereferenceableAttr(llfn, idx.as_uint(), deref); |
ff7c6d11 | 56 | } else { |
dfeec247 | 57 | llvm::LLVMRustAddDereferenceableOrNullAttr(llfn, idx.as_uint(), deref); |
ff7c6d11 XL |
58 | } |
59 | regular -= ArgAttribute::NonNull; | |
476ff2be | 60 | } |
ff7c6d11 | 61 | if let Some(align) = self.pointee_align { |
dfeec247 | 62 | llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32); |
ff7c6d11 | 63 | } |
416331ca XL |
64 | if regular.contains(ArgAttribute::ByVal) { |
65 | llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap()); | |
66 | } | |
ff7c6d11 | 67 | regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn)); |
476ff2be SL |
68 | } |
69 | } | |
70 | ||
416331ca | 71 | fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) { |
ff7c6d11 | 72 | let mut regular = self.regular; |
476ff2be | 73 | unsafe { |
ff7c6d11 XL |
74 | let deref = self.pointee_size.bytes(); |
75 | if deref != 0 { | |
76 | if regular.contains(ArgAttribute::NonNull) { | |
dfeec247 | 77 | llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite, idx.as_uint(), deref); |
ff7c6d11 | 78 | } else { |
dfeec247 XL |
79 | llvm::LLVMRustAddDereferenceableOrNullCallSiteAttr( |
80 | callsite, | |
81 | idx.as_uint(), | |
82 | deref, | |
83 | ); | |
ff7c6d11 XL |
84 | } |
85 | regular -= ArgAttribute::NonNull; | |
86 | } | |
87 | if let Some(align) = self.pointee_align { | |
dfeec247 XL |
88 | llvm::LLVMRustAddAlignmentCallSiteAttr( |
89 | callsite, | |
90 | idx.as_uint(), | |
91 | align.bytes() as u32, | |
92 | ); | |
476ff2be | 93 | } |
416331ca XL |
94 | if regular.contains(ArgAttribute::ByVal) { |
95 | llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap()); | |
96 | } | |
ff7c6d11 | 97 | regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite)); |
476ff2be SL |
98 | } |
99 | } | |
100 | } | |
cc61c64b | 101 | |
83c7162d | 102 | pub trait LlvmType { |
b7449926 | 103 | fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type; |
cc61c64b XL |
104 | } |
105 | ||
83c7162d | 106 | impl LlvmType for Reg { |
b7449926 | 107 | fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type { |
cc61c64b | 108 | match self.kind { |
a1dfa0c6 | 109 | RegKind::Integer => cx.type_ix(self.size.bits()), |
dfeec247 XL |
110 | RegKind::Float => match self.size.bits() { |
111 | 32 => cx.type_f32(), | |
112 | 64 => cx.type_f64(), | |
113 | _ => bug!("unsupported float: {:?}", self), | |
114 | }, | |
115 | RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()), | |
cc61c64b XL |
116 | } |
117 | } | |
118 | } | |
119 | ||
83c7162d | 120 | impl LlvmType for CastTarget { |
b7449926 | 121 | fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type { |
0531ce1d | 122 | let rest_ll_unit = self.rest.unit.llvm_type(cx); |
94b46f34 XL |
123 | let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 { |
124 | (0, 0) | |
125 | } else { | |
dfeec247 XL |
126 | ( |
127 | self.rest.total.bytes() / self.rest.unit.size.bytes(), | |
128 | self.rest.total.bytes() % self.rest.unit.size.bytes(), | |
129 | ) | |
94b46f34 | 130 | }; |
0531ce1d XL |
131 | |
132 | if self.prefix.iter().all(|x| x.is_none()) { | |
133 | // Simplify to a single unit when there is no prefix and size <= unit size | |
134 | if self.rest.total <= self.rest.unit.size { | |
135 | return rest_ll_unit; | |
136 | } | |
137 | ||
138 | // Simplify to array when all chunks are the same size and type | |
139 | if rem_bytes == 0 { | |
a1dfa0c6 | 140 | return cx.type_array(rest_ll_unit, rest_count); |
cc61c64b XL |
141 | } |
142 | } | |
0531ce1d XL |
143 | |
144 | // Create list of fields in the main structure | |
dfeec247 XL |
145 | let mut args: Vec<_> = self |
146 | .prefix | |
147 | .iter() | |
148 | .flat_map(|option_kind| { | |
74b04a01 | 149 | option_kind.map(|kind| Reg { kind, size: self.prefix_chunk }.llvm_type(cx)) |
dfeec247 | 150 | }) |
0531ce1d XL |
151 | .chain((0..rest_count).map(|_| rest_ll_unit)) |
152 | .collect(); | |
153 | ||
154 | // Append final integer | |
155 | if rem_bytes != 0 { | |
156 | // Only integers can be really split further. | |
157 | assert_eq!(self.rest.unit.kind, RegKind::Integer); | |
a1dfa0c6 | 158 | args.push(cx.type_ix(rem_bytes * 8)); |
0531ce1d XL |
159 | } |
160 | ||
a1dfa0c6 | 161 | cx.type_struct(&args, false) |
cc61c64b XL |
162 | } |
163 | } | |
476ff2be | 164 | |
60c5eb7d | 165 | pub trait ArgAbiExt<'ll, 'tcx> { |
b7449926 | 166 | fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; |
a1dfa0c6 XL |
167 | fn store( |
168 | &self, | |
169 | bx: &mut Builder<'_, 'll, 'tcx>, | |
170 | val: &'ll Value, | |
171 | dst: PlaceRef<'tcx, &'ll Value>, | |
172 | ); | |
173 | fn store_fn_arg( | |
174 | &self, | |
175 | bx: &mut Builder<'_, 'll, 'tcx>, | |
176 | idx: &mut usize, | |
177 | dst: PlaceRef<'tcx, &'ll Value>, | |
178 | ); | |
54a0048b SL |
179 | } |
180 | ||
60c5eb7d | 181 | impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { |
9fa01778 | 182 | /// Gets the LLVM type for a place of the original Rust type of |
0731742a | 183 | /// this argument/return, i.e., the result of `type_of::type_of`. |
b7449926 | 184 | fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { |
2c00a5a8 | 185 | self.layout.llvm_type(cx) |
54a0048b SL |
186 | } |
187 | ||
60c5eb7d | 188 | /// Stores a direct/indirect value described by this ArgAbi into a |
ff7c6d11 | 189 | /// place for the original Rust type of this argument/return. |
54a0048b SL |
190 | /// Can be used for both storing formal arguments into Rust variables |
191 | /// or results of call/invoke instructions into their destinations. | |
a1dfa0c6 XL |
192 | fn store( |
193 | &self, | |
194 | bx: &mut Builder<'_, 'll, 'tcx>, | |
195 | val: &'ll Value, | |
196 | dst: PlaceRef<'tcx, &'ll Value>, | |
197 | ) { | |
54a0048b SL |
198 | if self.is_ignore() { |
199 | return; | |
200 | } | |
b7449926 | 201 | if self.is_sized_indirect() { |
a1dfa0c6 | 202 | OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) |
b7449926 | 203 | } else if self.is_unsized_indirect() { |
60c5eb7d | 204 | bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); |
ff7c6d11 | 205 | } else if let PassMode::Cast(cast) = self.mode { |
a7813a04 XL |
206 | // FIXME(eddyb): Figure out when the simpler Store is safe, clang |
207 | // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. | |
208 | let can_store_through_cast_ptr = false; | |
209 | if can_store_through_cast_ptr { | |
a1dfa0c6 XL |
210 | let cast_ptr_llty = bx.type_ptr_to(cast.llvm_type(bx)); |
211 | let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty); | |
212 | bx.store(val, cast_dst, self.layout.align.abi); | |
a7813a04 XL |
213 | } else { |
214 | // The actual return type is a struct, but the ABI | |
215 | // adaptation code has cast it into some scalar type. The | |
216 | // code that follows is the only reliable way I have | |
217 | // found to do a transform like i64 -> {i32,i32}. | |
218 | // Basically we dump the data onto the stack then memcpy it. | |
219 | // | |
220 | // Other approaches I tried: | |
221 | // - Casting rust ret pointer to the foreign type and using Store | |
222 | // is (a) unsafe if size of foreign type > size of rust type and | |
223 | // (b) runs afoul of strict aliasing rules, yielding invalid | |
224 | // assembly under -O (specifically, the store gets removed). | |
225 | // - Truncating foreign type to correct integral type and then | |
226 | // bitcasting to the struct type yields invalid cast errors. | |
227 | ||
228 | // We instead thus allocate some scratch space... | |
a1dfa0c6 XL |
229 | let scratch_size = cast.size(bx); |
230 | let scratch_align = cast.align(bx); | |
e1599b0c | 231 | let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align); |
2c00a5a8 | 232 | bx.lifetime_start(llscratch, scratch_size); |
a7813a04 | 233 | |
60c5eb7d | 234 | // ... where we first store the value... |
2c00a5a8 | 235 | bx.store(val, llscratch, scratch_align); |
a7813a04 | 236 | |
60c5eb7d | 237 | // ... and then memcpy it to the intended destination. |
a1dfa0c6 XL |
238 | bx.memcpy( |
239 | dst.llval, | |
240 | self.layout.align.abi, | |
241 | llscratch, | |
242 | scratch_align, | |
243 | bx.const_usize(self.layout.size.bytes()), | |
dfeec247 | 244 | MemFlags::empty(), |
a1dfa0c6 | 245 | ); |
a7813a04 | 246 | |
2c00a5a8 | 247 | bx.lifetime_end(llscratch, scratch_size); |
54a0048b SL |
248 | } |
249 | } else { | |
2c00a5a8 | 250 | OperandValue::Immediate(val).store(bx, dst); |
54a0048b SL |
251 | } |
252 | } | |
253 | ||
a1dfa0c6 XL |
254 | fn store_fn_arg( |
255 | &self, | |
256 | bx: &mut Builder<'a, 'll, 'tcx>, | |
257 | idx: &mut usize, | |
258 | dst: PlaceRef<'tcx, &'ll Value>, | |
259 | ) { | |
ff7c6d11 | 260 | let mut next = || { |
2c00a5a8 | 261 | let val = llvm::get_param(bx.llfn(), *idx as c_uint); |
54a0048b | 262 | *idx += 1; |
ff7c6d11 XL |
263 | val |
264 | }; | |
265 | match self.mode { | |
e74abb32 | 266 | PassMode::Ignore => {} |
ff7c6d11 | 267 | PassMode::Pair(..) => { |
2c00a5a8 | 268 | OperandValue::Pair(next(), next()).store(bx, dst); |
ff7c6d11 | 269 | } |
b7449926 | 270 | PassMode::Indirect(_, Some(_)) => { |
a1dfa0c6 | 271 | OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); |
b7449926 XL |
272 | } |
273 | PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => { | |
532ac7d7 XL |
274 | let next_arg = next(); |
275 | self.store(bx, next_arg, dst); | |
ff7c6d11 | 276 | } |
54a0048b | 277 | } |
54a0048b SL |
278 | } |
279 | } | |
280 | ||
60c5eb7d | 281 | impl ArgAbiMethods<'tcx> for Builder<'a, 'll, 'tcx> { |
a1dfa0c6 XL |
282 | fn store_fn_arg( |
283 | &mut self, | |
60c5eb7d | 284 | arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, |
dfeec247 XL |
285 | idx: &mut usize, |
286 | dst: PlaceRef<'tcx, Self::Value>, | |
a1dfa0c6 | 287 | ) { |
60c5eb7d | 288 | arg_abi.store_fn_arg(self, idx, dst) |
a1dfa0c6 | 289 | } |
60c5eb7d | 290 | fn store_arg( |
a1dfa0c6 | 291 | &mut self, |
60c5eb7d | 292 | arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, |
a1dfa0c6 | 293 | val: &'ll Value, |
dfeec247 | 294 | dst: PlaceRef<'tcx, &'ll Value>, |
a1dfa0c6 | 295 | ) { |
60c5eb7d | 296 | arg_abi.store(self, val, dst) |
a1dfa0c6 | 297 | } |
60c5eb7d XL |
298 | fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> &'ll Type { |
299 | arg_abi.memory_ty(self) | |
a1dfa0c6 XL |
300 | } |
301 | } | |
302 | ||
60c5eb7d | 303 | pub trait FnAbiLlvmExt<'tcx> { |
b7449926 | 304 | fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; |
a1dfa0c6 | 305 | fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; |
83c7162d | 306 | fn llvm_cconv(&self) -> llvm::CallConv; |
416331ca | 307 | fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value); |
a1dfa0c6 | 308 | fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value); |
54a0048b SL |
309 | } |
310 | ||
60c5eb7d | 311 | impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { |
b7449926 | 312 | fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { |
8faf50e0 XL |
313 | let args_capacity: usize = self.args.iter().map(|arg| |
314 | if arg.pad.is_some() { 1 } else { 0 } + | |
315 | if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 } | |
316 | ).sum(); | |
317 | let mut llargument_tys = Vec::with_capacity( | |
dfeec247 | 318 | if let PassMode::Indirect(..) = self.ret.mode { 1 } else { 0 } + args_capacity, |
8faf50e0 | 319 | ); |
54a0048b | 320 | |
ff7c6d11 | 321 | let llreturn_ty = match self.ret.mode { |
e74abb32 | 322 | PassMode::Ignore => cx.type_void(), |
dfeec247 | 323 | PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx), |
2c00a5a8 | 324 | PassMode::Cast(cast) => cast.llvm_type(cx), |
b7449926 | 325 | PassMode::Indirect(..) => { |
a1dfa0c6 XL |
326 | llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); |
327 | cx.type_void() | |
ff7c6d11 | 328 | } |
54a0048b SL |
329 | }; |
330 | ||
331 | for arg in &self.args { | |
54a0048b SL |
332 | // add padding |
333 | if let Some(ty) = arg.pad { | |
2c00a5a8 | 334 | llargument_tys.push(ty.llvm_type(cx)); |
54a0048b SL |
335 | } |
336 | ||
ff7c6d11 | 337 | let llarg_ty = match arg.mode { |
e74abb32 | 338 | PassMode::Ignore => continue, |
2c00a5a8 | 339 | PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), |
ff7c6d11 | 340 | PassMode::Pair(..) => { |
8faf50e0 XL |
341 | llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); |
342 | llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); | |
ff7c6d11 XL |
343 | continue; |
344 | } | |
b7449926 XL |
345 | PassMode::Indirect(_, Some(_)) => { |
346 | let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty); | |
347 | let ptr_layout = cx.layout_of(ptr_ty); | |
348 | llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true)); | |
349 | llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); | |
350 | continue; | |
351 | } | |
2c00a5a8 | 352 | PassMode::Cast(cast) => cast.llvm_type(cx), |
a1dfa0c6 | 353 | PassMode::Indirect(_, None) => cx.type_ptr_to(arg.memory_ty(cx)), |
54a0048b | 354 | }; |
54a0048b SL |
355 | llargument_tys.push(llarg_ty); |
356 | } | |
357 | ||
532ac7d7 | 358 | if self.c_variadic { |
a1dfa0c6 | 359 | cx.type_variadic_func(&llargument_tys, llreturn_ty) |
54a0048b | 360 | } else { |
a1dfa0c6 XL |
361 | cx.type_func(&llargument_tys, llreturn_ty) |
362 | } | |
363 | } | |
364 | ||
365 | fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { | |
366 | unsafe { | |
dfeec247 XL |
367 | llvm::LLVMPointerType( |
368 | self.llvm_type(cx), | |
3dfed10e | 369 | cx.data_layout().instruction_address_space.0 as c_uint, |
dfeec247 | 370 | ) |
54a0048b SL |
371 | } |
372 | } | |
373 | ||
83c7162d XL |
374 | fn llvm_cconv(&self) -> llvm::CallConv { |
375 | match self.conv { | |
60c5eb7d | 376 | Conv::C | Conv::Rust => llvm::CCallConv, |
8faf50e0 | 377 | Conv::AmdGpuKernel => llvm::AmdGpuKernel, |
f035d41b XL |
378 | Conv::AvrInterrupt => llvm::AvrInterrupt, |
379 | Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, | |
83c7162d XL |
380 | Conv::ArmAapcs => llvm::ArmAapcsCallConv, |
381 | Conv::Msp430Intr => llvm::Msp430Intr, | |
382 | Conv::PtxKernel => llvm::PtxKernel, | |
383 | Conv::X86Fastcall => llvm::X86FastcallCallConv, | |
384 | Conv::X86Intr => llvm::X86_Intr, | |
385 | Conv::X86Stdcall => llvm::X86StdcallCallConv, | |
386 | Conv::X86ThisCall => llvm::X86_ThisCall, | |
387 | Conv::X86VectorCall => llvm::X86_VectorCall, | |
388 | Conv::X86_64SysV => llvm::X86_64_SysV, | |
389 | Conv::X86_64Win64 => llvm::X86_64_Win64, | |
390 | } | |
391 | } | |
392 | ||
416331ca | 393 | fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) { |
60c5eb7d XL |
394 | // FIXME(eddyb) can this also be applied to callsites? |
395 | if self.ret.layout.abi.is_uninhabited() { | |
396 | llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn); | |
397 | } | |
398 | ||
ba9703b0 XL |
399 | // FIXME(eddyb, wesleywiser): apply this to callsites as well? |
400 | if !self.can_unwind { | |
401 | llvm::Attribute::NoUnwind.apply_llfn(llvm::AttributePlace::Function, llfn); | |
402 | } | |
403 | ||
ff7c6d11 | 404 | let mut i = 0; |
416331ca XL |
405 | let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| { |
406 | attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty); | |
ff7c6d11 XL |
407 | i += 1; |
408 | }; | |
409 | match self.ret.mode { | |
410 | PassMode::Direct(ref attrs) => { | |
416331ca | 411 | attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None); |
ff7c6d11 | 412 | } |
416331ca | 413 | PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))), |
ff7c6d11 | 414 | _ => {} |
54a0048b | 415 | } |
54a0048b | 416 | for arg in &self.args { |
ff7c6d11 | 417 | if arg.pad.is_some() { |
416331ca | 418 | apply(&ArgAttributes::new(), None); |
ff7c6d11 XL |
419 | } |
420 | match arg.mode { | |
e74abb32 | 421 | PassMode::Ignore => {} |
dfeec247 XL |
422 | PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => { |
423 | apply(attrs, Some(arg.layout.llvm_type(cx))) | |
424 | } | |
b7449926 | 425 | PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { |
416331ca XL |
426 | apply(attrs, None); |
427 | apply(extra_attrs, None); | |
b7449926 | 428 | } |
ff7c6d11 | 429 | PassMode::Pair(ref a, ref b) => { |
416331ca XL |
430 | apply(a, None); |
431 | apply(b, None); | |
ff7c6d11 | 432 | } |
416331ca | 433 | PassMode::Cast(_) => apply(&ArgAttributes::new(), None), |
54a0048b SL |
434 | } |
435 | } | |
436 | } | |
437 | ||
a1dfa0c6 | 438 | fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) { |
ba9703b0 XL |
439 | // FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite. |
440 | ||
ff7c6d11 | 441 | let mut i = 0; |
416331ca XL |
442 | let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| { |
443 | attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty); | |
ff7c6d11 XL |
444 | i += 1; |
445 | }; | |
446 | match self.ret.mode { | |
447 | PassMode::Direct(ref attrs) => { | |
416331ca | 448 | attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None); |
ff7c6d11 | 449 | } |
416331ca | 450 | PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))), |
ff7c6d11 | 451 | _ => {} |
54a0048b | 452 | } |
ba9703b0 | 453 | if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi { |
83c7162d XL |
454 | // If the value is a boolean, the range is 0..2 and that ultimately |
455 | // become 0..0 when the type becomes i1, which would be rejected | |
456 | // by the LLVM verifier. | |
ba9703b0 | 457 | if let Int(..) = scalar.value { |
0bf4aa26 | 458 | if !scalar.is_bool() { |
a1dfa0c6 | 459 | let range = scalar.valid_range_exclusive(bx); |
83c7162d | 460 | if range.start != range.end { |
8faf50e0 | 461 | bx.range_metadata(callsite, range); |
83c7162d XL |
462 | } |
463 | } | |
83c7162d XL |
464 | } |
465 | } | |
54a0048b | 466 | for arg in &self.args { |
ff7c6d11 | 467 | if arg.pad.is_some() { |
416331ca | 468 | apply(&ArgAttributes::new(), None); |
ff7c6d11 XL |
469 | } |
470 | match arg.mode { | |
e74abb32 | 471 | PassMode::Ignore => {} |
dfeec247 XL |
472 | PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => { |
473 | apply(attrs, Some(arg.layout.llvm_type(bx))) | |
474 | } | |
b7449926 | 475 | PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { |
416331ca XL |
476 | apply(attrs, None); |
477 | apply(extra_attrs, None); | |
b7449926 | 478 | } |
ff7c6d11 | 479 | PassMode::Pair(ref a, ref b) => { |
416331ca XL |
480 | apply(a, None); |
481 | apply(b, None); | |
ff7c6d11 | 482 | } |
416331ca | 483 | PassMode::Cast(_) => apply(&ArgAttributes::new(), None), |
54a0048b SL |
484 | } |
485 | } | |
486 | ||
83c7162d XL |
487 | let cconv = self.llvm_cconv(); |
488 | if cconv != llvm::CCallConv { | |
489 | llvm::SetInstructionCallConv(callsite, cconv); | |
54a0048b SL |
490 | } |
491 | } | |
492 | } | |
a1dfa0c6 | 493 | |
a1dfa0c6 | 494 | impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { |
dfeec247 | 495 | fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value) { |
60c5eb7d | 496 | fn_abi.apply_attrs_callsite(self, callsite) |
a1dfa0c6 | 497 | } |
532ac7d7 XL |
498 | |
499 | fn get_param(&self, index: usize) -> Self::Value { | |
500 | llvm::get_param(self.llfn(), index as c_uint) | |
501 | } | |
a1dfa0c6 | 502 | } |