@@ -203,57 +203,63 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
203203 val : & ' ll Value ,
204204 dst : PlaceRef < ' tcx , & ' ll Value > ,
205205 ) {
206- if self . is_ignore ( ) {
207- return ;
208- }
209- if self . is_sized_indirect ( ) {
210- OperandValue :: Ref ( val, None , self . layout . align . abi ) . store ( bx, dst)
211- } else if self . is_unsized_indirect ( ) {
212- bug ! ( "unsized `ArgAbi` must be handled through `store_fn_arg`" ) ;
213- } else if let PassMode :: Cast { cast, pad_i32 : _ } = & self . mode {
214- // FIXME(eddyb): Figure out when the simpler Store is safe, clang
215- // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
216- let can_store_through_cast_ptr = false ;
217- if can_store_through_cast_ptr {
218- bx. store ( val, dst. llval , self . layout . align . abi ) ;
219- } else {
220- // The actual return type is a struct, but the ABI
221- // adaptation code has cast it into some scalar type. The
222- // code that follows is the only reliable way I have
223- // found to do a transform like i64 -> {i32,i32}.
224- // Basically we dump the data onto the stack then memcpy it.
225- //
226- // Other approaches I tried:
227- // - Casting rust ret pointer to the foreign type and using Store
228- // is (a) unsafe if size of foreign type > size of rust type and
229- // (b) runs afoul of strict aliasing rules, yielding invalid
230- // assembly under -O (specifically, the store gets removed).
231- // - Truncating foreign type to correct integral type and then
232- // bitcasting to the struct type yields invalid cast errors.
233-
234- // We instead thus allocate some scratch space...
235- let scratch_size = cast. size ( bx) ;
236- let scratch_align = cast. align ( bx) ;
237- let llscratch = bx. alloca ( cast. llvm_type ( bx) , scratch_align) ;
238- bx. lifetime_start ( llscratch, scratch_size) ;
239-
240- // ... where we first store the value...
241- bx. store ( val, llscratch, scratch_align) ;
242-
243- // ... and then memcpy it to the intended destination.
244- bx. memcpy (
245- dst. llval ,
246- self . layout . align . abi ,
247- llscratch,
248- scratch_align,
249- bx. const_usize ( self . layout . size . bytes ( ) ) ,
250- MemFlags :: empty ( ) ,
251- ) ;
206+ match & self . mode {
207+ PassMode :: Ignore => { }
208+ // Sized indirect arguments
209+ PassMode :: Indirect { attrs, meta_attrs : None , on_stack : _ } => {
210+ let align = attrs. pointee_align . unwrap_or ( self . layout . align . abi ) ;
211+ OperandValue :: Ref ( val, None , align) . store ( bx, dst) ;
212+ }
213+ // Unsized indirect qrguments
214+ PassMode :: Indirect { attrs : _, meta_attrs : Some ( _) , on_stack : _ } => {
215+ bug ! ( "unsized `ArgAbi` must be handled through `store_fn_arg`" ) ;
216+ }
217+ PassMode :: Cast { cast, pad_i32 : _ } => {
218+ // FIXME(eddyb): Figure out when the simpler Store is safe, clang
219+ // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
220+ let can_store_through_cast_ptr = false ;
221+ if can_store_through_cast_ptr {
222+ bx. store ( val, dst. llval , self . layout . align . abi ) ;
223+ } else {
224+ // The actual return type is a struct, but the ABI
225+ // adaptation code has cast it into some scalar type. The
226+ // code that follows is the only reliable way I have
227+ // found to do a transform like i64 -> {i32,i32}.
228+ // Basically we dump the data onto the stack then memcpy it.
229+ //
230+ // Other approaches I tried:
231+ // - Casting rust ret pointer to the foreign type and using Store
232+ // is (a) unsafe if size of foreign type > size of rust type and
233+ // (b) runs afoul of strict aliasing rules, yielding invalid
234+ // assembly under -O (specifically, the store gets removed).
235+ // - Truncating foreign type to correct integral type and then
236+ // bitcasting to the struct type yields invalid cast errors.
237+
238+ // We instead thus allocate some scratch space...
239+ let scratch_size = cast. size ( bx) ;
240+ let scratch_align = cast. align ( bx) ;
241+ let llscratch = bx. alloca ( cast. llvm_type ( bx) , scratch_align) ;
242+ bx. lifetime_start ( llscratch, scratch_size) ;
243+
244+ // ... where we first store the value...
245+ bx. store ( val, llscratch, scratch_align) ;
246+
247+ // ... and then memcpy it to the intended destination.
248+ bx. memcpy (
249+ dst. llval ,
250+ self . layout . align . abi ,
251+ llscratch,
252+ scratch_align,
253+ bx. const_usize ( self . layout . size . bytes ( ) ) ,
254+ MemFlags :: empty ( ) ,
255+ ) ;
252256
253- bx. lifetime_end ( llscratch, scratch_size) ;
257+ bx. lifetime_end ( llscratch, scratch_size) ;
258+ }
259+ }
260+ _ => {
261+ OperandRef :: from_immediate_or_packed_pair ( bx, val, self . layout ) . val . store ( bx, dst) ;
254262 }
255- } else {
256- OperandRef :: from_immediate_or_packed_pair ( bx, val, self . layout ) . val . store ( bx, dst) ;
257263 }
258264 }
259265
0 commit comments