fn store(&self, bx: &Builder<'_, 'll, 'tcx>, val: &'ll Value, dst: PlaceRef<'ll, 'tcx>) {
        if self.is_ignore() {
            return;
        }
        let cx = bx.cx;
        if self.is_sized_indirect() {
            OperandValue::Ref(val, None, self.layout.align).store(bx, dst)
        } else if self.is_unsized_indirect() {
            bug!("unsized ArgType must be handled through store_fn_arg");
        } else if let PassMode::Cast(cast) = self.mode {
            // FIXME(eddyb): Figure out when the simpler Store is safe, clang
            // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
            let can_store_through_cast_ptr = false;
            if can_store_through_cast_ptr {
                let cast_dst = bx.pointercast(dst.llval, cast.llvm_type(cx).ptr_to());
                bx.store(val, cast_dst, self.layout.align);
            } else {
                // The actual return type is a struct, but the ABI
                // adaptation code has cast it into some scalar type.  The
                // code that follows is the only reliable way I have
                // found to do a transform like i64 -> {i32,i32}.
                // Basically we dump the data onto the stack then memcpy it.
                //
                // Other approaches I tried:
                // - Casting rust ret pointer to the foreign type and using Store
                //   is (a) unsafe if size of foreign type > size of rust type and
                //   (b) runs afoul of strict aliasing rules, yielding invalid
                //   assembly under -O (specifically, the store gets removed).
                // - Truncating foreign type to correct integral type and then
                //   bitcasting to the struct type yields invalid cast errors.

                // We instead thus allocate some scratch space...
                let scratch_size = cast.size(cx);
                let scratch_align = cast.align(cx);
                let llscratch = bx.alloca(cast.llvm_type(cx), "abi_cast", scratch_align);
                bx.lifetime_start(llscratch, scratch_size);

                // ...where we first store the value...
                bx.store(val, llscratch, scratch_align);

                // ...and then memcpy it to the intended destination.
                base::call_memcpy(bx,
                                  bx.pointercast(dst.llval, Type::i8p(cx)),
                                  bx.pointercast(llscratch, Type::i8p(cx)),
                                  C_usize(cx, self.layout.size.bytes()),
                                  self.layout.align.min(scratch_align),
                                  MemFlags::empty());

                bx.lifetime_end(llscratch, scratch_size);
            }
        } else {
            OperandValue::Immediate(val).store(bx, dst);
        }
    }
/// Store a direct/indirect value described by this ArgType into a
/// place for the original Rust type of this argument/return.
/// Can be used for both storing formal arguments into Rust variables
/// or results of call/invoke instructions into their destinations.
Store a direct/indirect value described by this ArgType into a
place for the original Rust type of this argument/return.
Can be used for both storing formal arguments into Rust variables
or results of call/invoke instructions into their destinations.
Store a direct / indirect value described by this ArgType into a place for the original Rust type of this argument / return . Can be used for both storing formal arguments into Rust variables or results of call / invoke instructions into their destinations .
fn store(&self, bx: &Builder<'_, 'll, 'tcx>, val: &'ll Value, dst: PlaceRef<'ll, 'tcx>) {
        if self.is_ignore() {
            return;
        }
        let cx = bx.cx;
        if self.is_sized_indirect() {
            OperandValue::Ref(val, None, self.layout.align).store(bx, dst)
        } else if self.is_unsized_indirect() {
            bug!("unsized ArgType must be handled through store_fn_arg");
        } else if let PassMode::Cast(cast) = self.mode {
            // FIXME(eddyb): Figure out when the simpler Store is safe, clang
            // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
            let can_store_through_cast_ptr = false;
            if can_store_through_cast_ptr {
                let cast_dst = bx.pointercast(dst.llval, cast.llvm_type(cx).ptr_to());
                bx.store(val, cast_dst, self.layout.align);
            } else {
                // The actual return type is a struct, but the ABI
                // adaptation code has cast it into some scalar type.  The
                // code that follows is the only reliable way I have
                // found to do a transform like i64 -> {i32,i32}.
                // Basically we dump the data onto the stack then memcpy it.
                //
                // Other approaches I tried:
                // - Casting rust ret pointer to the foreign type and using Store
                //   is (a) unsafe if size of foreign type > size of rust type and
                //   (b) runs afoul of strict aliasing rules, yielding invalid
                //   assembly under -O (specifically, the store gets removed).
                // - Truncating foreign type to correct integral type and then
                //   bitcasting to the struct type yields invalid cast errors.
                // We instead thus allocate some scratch space...
                let scratch_size = cast.size(cx);
                let scratch_align = cast.align(cx);
                let llscratch = bx.alloca(cast.llvm_type(cx), "abi_cast", scratch_align);
                bx.lifetime_start(llscratch, scratch_size);
                // ...where we first store the value...
                bx.store(val, llscratch, scratch_align);
                // ...and then memcpy it to the intended destination.
                base::call_memcpy(bx,
                                  bx.pointercast(dst.llval, Type::i8p(cx)),
                                  bx.pointercast(llscratch, Type::i8p(cx)),
                                  C_usize(cx, self.layout.size.bytes()),
                                  self.layout.align.min(scratch_align),
                                  MemFlags::empty());
                bx.lifetime_end(llscratch, scratch_size);
            }
        } else {
            OperandValue::Immediate(val).store(bx, dst);
        }
    }
fn store ( & self , bx : & Builder < ' _ , ' ll , ' tcx > , val : & ' ll Value , dst : PlaceRef < ' ll , ' tcx > ) { if self . is_ignore ( ) { return ; } let cx = bx . cx ; if self . is_sized_indirect ( ) { OperandValue :: Ref ( val , None , self . layout . align ) . store ( bx , dst ) } else if self . is_unsized_indirect ( ) { bug ! ( " " ) ; } else if let PassMode :: Cast ( cast ) = self . mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false ; if can_store_through_cast_ptr { let cast_dst = bx . pointercast ( dst . llval , cast . llvm_type ( cx ) . ptr_to ( ) ) ; bx . store ( val , cast_dst , self . layout . align ) ; } else { // The actual return type is a struct, but the ABI // adaptation code has cast it into some scalar type.  The // code that follows is the only reliable way I have // found to do a transform like i64 -> {i32,i32}. // Basically we dump the data onto the stack then memcpy it. // // Other approaches I tried: // - Casting rust ret pointer to the foreign type and using Store //   is (a) unsafe if size of foreign type > size of rust type and //   (b) runs afoul of strict aliasing rules, yielding invalid //   assembly under -O (specifically, the store gets removed). // - Truncating foreign type to correct integral type and then //   bitcasting to the struct type yields invalid cast errors. // We instead thus allocate some scratch space... let scratch_size = cast . size ( cx ) ; let scratch_align = cast . align ( cx ) ; let llscratch = bx . alloca ( cast . llvm_type ( cx ) , " " , scratch_align ) ; bx . lifetime_start ( llscratch , scratch_size ) ; // ...where we first store the value... bx . store ( val , llscratch , scratch_align ) ; // ...and then memcpy it to the intended destination. base :: call_memcpy ( bx , bx . pointercast ( dst . llval , Type :: i8p ( cx ) ) , bx . pointercast ( llscratch , Type :: i8p ( cx ) ) , C_usize ( cx , self . layout . size . bytes ( ) ) , self . layout . align . min ( scratch_align ) , MemFlags :: empty ( ) ) ; bx . lifetime_end ( llscratch , scratch_size ) ; } } else { OperandValue :: Immediate ( val ) . store ( bx , dst ) ; } }
Store a direct/indirect value described by this ArgType into a
place for the original Rust type of this argument/return.
Store a direct / indirect value described by this ArgType into a place for the original Rust type of this argument / return .
&self
bx
&Builder<'_, 'll, 'tcx>
val
&'ll Value
dst
PlaceRef<'ll, 'tcx>
&self
bx
&Builder<'_, 'll, 'tcx>
val
&'ll Value
dst
PlaceRef<'ll, 'tcx>