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