@@ -650,31 +650,6 @@ impl Assembler
650650 * opnd = split_load_operand ( asm, * opnd) ;
651651 asm. push_insn ( insn) ;
652652 } ,
653- Insn :: Store { dest, src } => {
654- // The value being stored must be in a register, so if it's
655- // not already one we'll load it first.
656- let opnd1 = match src {
657- // If the first operand is zero, then we can just use
658- // the zero register.
659- Opnd :: UImm ( 0 ) | Opnd :: Imm ( 0 ) => Opnd :: Reg ( XZR_REG ) ,
660- // Otherwise we'll check if we need to load it first.
661- _ => split_load_operand ( asm, * src)
662- } ;
663-
664- match dest {
665- Opnd :: Reg ( _) => {
666- // Store does not support a register as a dest operand.
667- asm. mov ( * dest, opnd1) ;
668- }
669- _ => {
670- // The displacement for the STUR instruction can't be more
671- // than 9 bits long. If it's longer, we need to load the
672- // memory address into a register first.
673- let opnd0 = split_memory_address ( asm, * dest) ;
674- asm. store ( opnd0, opnd1) ;
675- }
676- }
677- } ,
678653 Insn :: Mul { left, right, .. } => {
679654 * left = split_load_operand ( asm, * left) ;
680655 * right = split_load_operand ( asm, * right) ;
@@ -1031,7 +1006,9 @@ impl Assembler
10311006 lsl ( cb, out. into ( ) , opnd. into ( ) , shift. into ( ) ) ;
10321007 } ,
10331008 store_insn @ Insn :: Store { dest, src } => {
1034- // Accepted forms: (Mem, Imm | UImm | Value | Reg) = (dest, src)
1009+ // With minor exceptions, as long as `dest` is a Mem, all forms of `src` are
1010+ // accepted. As a rule of thumb, avoid using Assembler::SCRATCH as a memory
1011+ // base register to gurantee things will work.
10351012 let & Opnd :: Mem ( Mem { num_bits : dest_num_bits, base : MemBase :: Reg ( base_reg_no) , disp } ) = dest else {
10361013 panic ! ( "Unexpected Insn::Store destination in arm64_emit: {dest:?}" ) ;
10371014 } ;
@@ -1707,6 +1684,64 @@ mod tests {
17071684 " ) ;
17081685 }
17091686
1687+ #[ test]
1688+ fn test_store ( ) {
1689+ let ( mut asm, mut cb) = setup_asm ( ) ;
1690+
1691+ // Large memory offsets in combinations of destination and source
1692+ let large_mem = Opnd :: mem ( 64 , NATIVE_STACK_PTR , -0x305 ) ;
1693+ let small_mem = Opnd :: mem ( 64 , C_RET_OPND , 0 ) ;
1694+ asm. store ( small_mem, large_mem) ;
1695+ asm. store ( large_mem, small_mem) ;
1696+ asm. store ( large_mem, large_mem) ;
1697+
1698+ asm. compile_with_num_regs ( & mut cb, 0 ) ;
1699+ assert_disasm ! ( cb, "f0170cd1100240f8100000f8100040f8f1170cd1300200f8f0170cd1100240f8f1170cd1300200f8" , "
1700+ 0x0: sub x16, sp, #0x305
1701+ 0x4: ldur x16, [x16]
1702+ 0x8: stur x16, [x0]
1703+ 0xc: ldur x16, [x0]
1704+ 0x10: sub x17, sp, #0x305
1705+ 0x14: stur x16, [x17]
1706+ 0x18: sub x16, sp, #0x305
1707+ 0x1c: ldur x16, [x16]
1708+ 0x20: sub x17, sp, #0x305
1709+ 0x24: stur x16, [x17]
1710+ " ) ;
1711+ }
1712+
1713+ #[ test]
1714+ fn test_store_value_without_split ( ) {
1715+ let ( mut asm, mut cb) = setup_asm ( ) ;
1716+
1717+ let imitation_heap_value = VALUE ( 0x1000 ) ;
1718+ assert ! ( imitation_heap_value. heap_object_p( ) ) ;
1719+ asm. store ( Opnd :: mem ( VALUE_BITS , SP , 0 ) , imitation_heap_value. into ( ) ) ;
1720+
1721+ // Side exit code are compiled without the split pass, so we directly call emit here to
1722+ // emulate that scenario.
1723+ let gc_offsets = asm. arm64_emit ( & mut cb) . unwrap ( ) ;
1724+ assert_eq ! ( 1 , gc_offsets. len( ) , "VALUE source operand should be reported as gc offset" ) ;
1725+
1726+ assert_disasm ! ( cb, "50000058030000140010000000000000b00200f8" , "
1727+ 0x0: ldr x16, #8
1728+ 0x4: b #0x10
1729+ 0x8: .byte 0x00, 0x10, 0x00, 0x00
1730+ 0xc: .byte 0x00, 0x00, 0x00, 0x00
1731+ 0x10: stur x16, [x21]
1732+ " ) ;
1733+ }
1734+
1735+ #[ test]
1736+ #[ should_panic]
1737+ fn test_store_unserviceable ( ) {
1738+ let ( mut asm, mut cb) = setup_asm ( ) ;
1739+ // This would put the source into SCRATCH_REG, messing up the destination
1740+ asm. store ( Opnd :: mem ( 64 , Opnd :: Reg ( Assembler :: SCRATCH_REG ) , 0 ) , 0x83902 . into ( ) ) ;
1741+
1742+ asm. compile_with_num_regs ( & mut cb, 0 ) ;
1743+ }
1744+
17101745 /*
17111746 #[test]
17121747 fn test_emit_lea_label() {
0 commit comments