@@ -203,57 +203,63 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
203
203
val : & ' ll Value ,
204
204
dst : PlaceRef < ' tcx , & ' ll Value > ,
205
205
) {
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
+ ) ;
252
256
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) ;
254
262
}
255
- } else {
256
- OperandRef :: from_immediate_or_packed_pair ( bx, val, self . layout ) . val . store ( bx, dst) ;
257
263
}
258
264
}
259
265
0 commit comments