1 use gccjit::{ToLValue, ToRValue, Type}; 2 use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; 3 use rustc_data_structures::fx::FxHashSet; 4 use rustc_middle::bug; 5 use rustc_middle::ty::Ty; 6 use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind}; 7 8 use crate::builder::Builder; 9 use crate::context::CodegenCx; 10 use crate::intrinsic::ArgAbiExt; 11 use crate::type_of::LayoutGccExt; 12 13 impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { get_param(&mut self, index: usize) -> Self::Value14 fn get_param(&mut self, index: usize) -> Self::Value { 15 let func = self.current_func(); 16 let param = func.get_param(index as i32); 17 let on_stack = 18 if let Some(on_stack_param_indices) = self.on_stack_function_params.borrow().get(&func) { 19 on_stack_param_indices.contains(&index) 20 } 21 else { 22 false 23 }; 24 if on_stack { 25 param.to_lvalue().get_address(None) 26 } 27 else { 28 param.to_rvalue() 29 } 30 } 31 } 32 33 impl GccType for CastTarget { gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>34 fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { 35 let rest_gcc_unit = self.rest.unit.gcc_type(cx); 36 let (rest_count, rem_bytes) = 37 if self.rest.unit.size.bytes() == 0 { 38 (0, 0) 39 } 40 else { 41 (self.rest.total.bytes() / self.rest.unit.size.bytes(), self.rest.total.bytes() % self.rest.unit.size.bytes()) 42 }; 43 44 if self.prefix.iter().all(|x| x.is_none()) { 45 // Simplify to a single unit when there is no prefix and size <= unit size 46 if self.rest.total <= self.rest.unit.size { 47 return rest_gcc_unit; 48 } 49 50 // Simplify to array when all chunks are the same size and type 51 if rem_bytes == 0 { 52 return cx.type_array(rest_gcc_unit, rest_count); 53 } 54 } 55 56 // Create list of fields in the main structure 57 let mut args: Vec<_> = self 58 .prefix 59 .iter() 60 .flat_map(|option_reg| { 61 option_reg.map(|reg| reg.gcc_type(cx)) 62 }) 63 .chain((0..rest_count).map(|_| rest_gcc_unit)) 64 .collect(); 65 66 // Append final integer 67 if rem_bytes != 0 { 68 // Only integers can be really split further. 69 assert_eq!(self.rest.unit.kind, RegKind::Integer); 70 args.push(cx.type_ix(rem_bytes * 8)); 71 } 72 73 cx.type_struct(&args, false) 74 } 75 } 76 77 pub trait GccType { gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>78 fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>; 79 } 80 81 impl GccType for Reg { gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>82 fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { 83 match self.kind { 84 RegKind::Integer => cx.type_ix(self.size.bits()), 85 RegKind::Float => { 86 match self.size.bits() { 87 32 => cx.type_f32(), 88 64 => cx.type_f64(), 89 _ => bug!("unsupported float: {:?}", self), 90 } 91 }, 92 RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()), 93 } 94 } 95 } 96 97 pub trait FnAbiGccExt<'gcc, 'tcx> { 98 // TODO(antoyo): return a function pointer type instead? gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>)99 fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>); ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>100 fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; 101 } 102 103 impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>)104 fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>) { 105 let mut on_stack_param_indices = FxHashSet::default(); 106 107 // This capacity calculation is approximate. 108 let mut argument_tys = Vec::with_capacity( 109 self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } 110 ); 111 112 let return_ty = 113 match self.ret.mode { 114 PassMode::Ignore => cx.type_void(), 115 PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), 116 PassMode::Cast(ref cast, _) => cast.gcc_type(cx), 117 PassMode::Indirect { .. } => { 118 argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); 119 cx.type_void() 120 } 121 }; 122 123 for arg in self.args.iter() { 124 let arg_ty = match arg.mode { 125 PassMode::Ignore => continue, 126 PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), 127 PassMode::Pair(..) => { 128 argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true)); 129 argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true)); 130 continue; 131 } 132 PassMode::Indirect { extra_attrs: Some(_), .. } => { 133 unimplemented!(); 134 } 135 PassMode::Cast(ref cast, pad_i32) => { 136 // add padding 137 if pad_i32 { 138 argument_tys.push(Reg::i32().gcc_type(cx)); 139 } 140 cast.gcc_type(cx) 141 } 142 PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => { 143 on_stack_param_indices.insert(argument_tys.len()); 144 arg.memory_ty(cx) 145 }, 146 PassMode::Indirect { extra_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)), 147 }; 148 argument_tys.push(arg_ty); 149 } 150 151 (return_ty, argument_tys, self.c_variadic, on_stack_param_indices) 152 } 153 ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>154 fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { 155 let (return_type, params, variadic, on_stack_param_indices) = self.gcc_type(cx); 156 let pointer_type = cx.context.new_function_pointer_type(None, return_type, ¶ms, variadic); 157 cx.on_stack_params.borrow_mut().insert(pointer_type.dyncast_function_ptr_type().expect("function ptr type"), on_stack_param_indices); 158 pointer_type 159 } 160 } 161