pub(crate) fn lower_address<C: LowerCtx<I = Inst>>(
    ctx: &mut C,
    elem_ty: Type,
    roots: &[InsnInput],
    offset: i32,
) -> AMode {
    // TODO: support base_reg + scale * index_reg. For this, we would need to pattern-match shl or
    // mul instructions (Load/StoreComplex don't include scale factors).

    // Collect addends through an arbitrary tree of 32-to-64-bit sign/zero
    // extends and addition ops. We update these as we consume address
    // components, so they represent the remaining addends not yet handled.
    let (mut addends64, mut addends32, args_offset) = collect_address_addends(ctx, roots);
    let mut offset = args_offset + (offset as i64);

    trace!(
        "lower_address: addends64 {:?}, addends32 {:?}, offset {}",
        addends64,
        addends32,
        offset
    );

    // First, decide what the `AMode` will be. Take one extendee and one 64-bit
    // reg, or two 64-bit regs, or a 64-bit reg and a 32-bit reg with extension,
    // or some other combination as appropriate.
    let memarg = if addends64.len() > 0 {
        if addends32.len() > 0 {
            let (reg32, extendop) = addends32.pop().unwrap();
            let reg64 = addends64.pop().unwrap();
            AMode::RegExtended(reg64, reg32, extendop)
        } else if offset > 0 && offset < 0x1000 {
            let reg64 = addends64.pop().unwrap();
            let off = offset;
            offset = 0;
            AMode::RegOffset(reg64, off, elem_ty)
        } else if addends64.len() >= 2 {
            let reg1 = addends64.pop().unwrap();
            let reg2 = addends64.pop().unwrap();
            AMode::RegReg(reg1, reg2)
        } else {
            let reg1 = addends64.pop().unwrap();
            AMode::reg(reg1)
        }
    } else
    /* addends64.len() == 0 */
    {
        if addends32.len() > 0 {
            let tmp = ctx.alloc_tmp(RegClass::I64, I64);
            let (reg1, extendop) = addends32.pop().unwrap();
            let signed = match extendop {
                ExtendOp::SXTW => true,
                ExtendOp::UXTW => false,
                _ => unreachable!(),
            };
            ctx.emit(Inst::Extend {
                rd: tmp,
                rn: reg1,
                signed,
                from_bits: 32,
                to_bits: 64,
            });
            if let Some((reg2, extendop)) = addends32.pop() {
                AMode::RegExtended(tmp.to_reg(), reg2, extendop)
            } else {
                AMode::reg(tmp.to_reg())
            }
        } else
        /* addends32.len() == 0 */
        {
            let off_reg = ctx.alloc_tmp(RegClass::I64, I64);
            lower_constant_u64(ctx, off_reg, offset as u64);
            offset = 0;
            AMode::reg(off_reg.to_reg())
        }
    };

    // At this point, if we have any remaining components, we need to allocate a
    // temp, replace one of the registers in the AMode with the temp, and emit
    // instructions to add together the remaining components. Return immediately
    // if this is *not* the case.
    if offset == 0 && addends32.len() == 0 && addends64.len() == 0 {
        return memarg;
    }

    // Allocate the temp and shoehorn it into the AMode.
    let addr = ctx.alloc_tmp(RegClass::I64, I64);
    let (reg, memarg) = match memarg {
        AMode::RegExtended(r1, r2, extendop) => {
            (r1, AMode::RegExtended(addr.to_reg(), r2, extendop))
        }
        AMode::RegOffset(r, off, ty) => (r, AMode::RegOffset(addr.to_reg(), off, ty)),
        AMode::RegReg(r1, r2) => (r2, AMode::RegReg(addr.to_reg(), r1)),
        AMode::UnsignedOffset(r, imm) => (r, AMode::UnsignedOffset(addr.to_reg(), imm)),
        _ => unreachable!(),
    };

    // If there is any offset, load that first into `addr`, and add the `reg`
    // that we kicked out of the `AMode`; otherwise, start with that reg.
    if offset != 0 {
        // If we can fit offset or -offset in an imm12, use an add-imm
        // to combine the reg and offset. Otherwise, load value first then add.
        if let Some(imm12) = Imm12::maybe_from_u64(offset as u64) {
            ctx.emit(Inst::AluRRImm12 {
                alu_op: ALUOp::Add64,
                rd: addr,
                rn: reg,
                imm12,
            });
        } else if let Some(imm12) = Imm12::maybe_from_u64(offset.wrapping_neg() as u64) {
            ctx.emit(Inst::AluRRImm12 {
                alu_op: ALUOp::Sub64,
                rd: addr,
                rn: reg,
                imm12,
            });
        } else {
            lower_constant_u64(ctx, addr, offset as u64);
            ctx.emit(Inst::AluRRR {
                alu_op: ALUOp::Add64,
                rd: addr,
                rn: addr.to_reg(),
                rm: reg,
            });
        }
    } else {
        ctx.emit(Inst::gen_move(addr, reg, I64));
    }

    // Now handle reg64 and reg32-extended components.
    for reg in addends64 {
        // If the register is the stack reg, we must move it to another reg
        // before adding it.
        let reg = if reg == stack_reg() {
            let tmp = ctx.alloc_tmp(RegClass::I64, I64);
            ctx.emit(Inst::gen_move(tmp, stack_reg(), I64));
            tmp.to_reg()
        } else {
            reg
        };
        ctx.emit(Inst::AluRRR {
            alu_op: ALUOp::Add64,
            rd: addr,
            rn: addr.to_reg(),
            rm: reg,
        });
    }
    for (reg, extendop) in addends32 {
        assert!(reg != stack_reg());
        ctx.emit(Inst::AluRRRExtend {
            alu_op: ALUOp::Add64,
            rd: addr,
            rn: addr.to_reg(),
            rm: reg,
            extendop,
        });
    }

    memarg
}
/// Lower the address of a load or store.
Lower the address of a load or store.
Lower the address of a load or store .
pub(crate) fn lower_address<C: LowerCtx<I = Inst>>(
    ctx: &mut C,
    elem_ty: Type,
    roots: &[InsnInput],
    offset: i32,
) -> AMode {
    // TODO: support base_reg + scale * index_reg. For this, we would need to pattern-match shl or
    // mul instructions (Load/StoreComplex don't include scale factors).
    // Collect addends through an arbitrary tree of 32-to-64-bit sign/zero
    // extends and addition ops. We update these as we consume address
    // components, so they represent the remaining addends not yet handled.
    let (mut addends64, mut addends32, args_offset) = collect_address_addends(ctx, roots);
    let mut offset = args_offset + (offset as i64);
    trace!(
        "lower_address: addends64 {:?}, addends32 {:?}, offset {}",
        addends64,
        addends32,
        offset
    );
    // First, decide what the `AMode` will be. Take one extendee and one 64-bit
    // reg, or two 64-bit regs, or a 64-bit reg and a 32-bit reg with extension,
    // or some other combination as appropriate.
    let memarg = if addends64.len() > 0 {
        if addends32.len() > 0 {
            let (reg32, extendop) = addends32.pop().unwrap();
            let reg64 = addends64.pop().unwrap();
            AMode::RegExtended(reg64, reg32, extendop)
        } else if offset > 0 && offset < 0x1000 {
            let reg64 = addends64.pop().unwrap();
            let off = offset;
            offset = 0;
            AMode::RegOffset(reg64, off, elem_ty)
        } else if addends64.len() >= 2 {
            let reg1 = addends64.pop().unwrap();
            let reg2 = addends64.pop().unwrap();
            AMode::RegReg(reg1, reg2)
        } else {
            let reg1 = addends64.pop().unwrap();
            AMode::reg(reg1)
        }
    } else
    /* addends64.len() == 0 */
    {
        if addends32.len() > 0 {
            let tmp = ctx.alloc_tmp(RegClass::I64, I64);
            let (reg1, extendop) = addends32.pop().unwrap();
            let signed = match extendop {
                ExtendOp::SXTW => true,
                ExtendOp::UXTW => false,
                _ => unreachable!(),
            };
            ctx.emit(Inst::Extend {
                rd: tmp,
                rn: reg1,
                signed,
                from_bits: 32,
                to_bits: 64,
            });
            if let Some((reg2, extendop)) = addends32.pop() {
                AMode::RegExtended(tmp.to_reg(), reg2, extendop)
            } else {
                AMode::reg(tmp.to_reg())
            }
        } else
        /* addends32.len() == 0 */
        {
            let off_reg = ctx.alloc_tmp(RegClass::I64, I64);
            lower_constant_u64(ctx, off_reg, offset as u64);
            offset = 0;
            AMode::reg(off_reg.to_reg())
        }
    };
    // At this point, if we have any remaining components, we need to allocate a
    // temp, replace one of the registers in the AMode with the temp, and emit
    // instructions to add together the remaining components. Return immediately
    // if this is *not* the case.
    if offset == 0 && addends32.len() == 0 && addends64.len() == 0 {
        return memarg;
    }
    // Allocate the temp and shoehorn it into the AMode.
    let addr = ctx.alloc_tmp(RegClass::I64, I64);
    let (reg, memarg) = match memarg {
        AMode::RegExtended(r1, r2, extendop) => {
            (r1, AMode::RegExtended(addr.to_reg(), r2, extendop))
        }
        AMode::RegOffset(r, off, ty) => (r, AMode::RegOffset(addr.to_reg(), off, ty)),
        AMode::RegReg(r1, r2) => (r2, AMode::RegReg(addr.to_reg(), r1)),
        AMode::UnsignedOffset(r, imm) => (r, AMode::UnsignedOffset(addr.to_reg(), imm)),
        _ => unreachable!(),
    };
    // If there is any offset, load that first into `addr`, and add the `reg`
    // that we kicked out of the `AMode`; otherwise, start with that reg.
    if offset != 0 {
        // If we can fit offset or -offset in an imm12, use an add-imm
        // to combine the reg and offset. Otherwise, load value first then add.
        if let Some(imm12) = Imm12::maybe_from_u64(offset as u64) {
            ctx.emit(Inst::AluRRImm12 {
                alu_op: ALUOp::Add64,
                rd: addr,
                rn: reg,
                imm12,
            });
        } else if let Some(imm12) = Imm12::maybe_from_u64(offset.wrapping_neg() as u64) {
            ctx.emit(Inst::AluRRImm12 {
                alu_op: ALUOp::Sub64,
                rd: addr,
                rn: reg,
                imm12,
            });
        } else {
            lower_constant_u64(ctx, addr, offset as u64);
            ctx.emit(Inst::AluRRR {
                alu_op: ALUOp::Add64,
                rd: addr,
                rn: addr.to_reg(),
                rm: reg,
            });
        }
    } else {
        ctx.emit(Inst::gen_move(addr, reg, I64));
    }
    // Now handle reg64 and reg32-extended components.
    for reg in addends64 {
        // If the register is the stack reg, we must move it to another reg
        // before adding it.
        let reg = if reg == stack_reg() {
            let tmp = ctx.alloc_tmp(RegClass::I64, I64);
            ctx.emit(Inst::gen_move(tmp, stack_reg(), I64));
            tmp.to_reg()
        } else {
            reg
        };
        ctx.emit(Inst::AluRRR {
            alu_op: ALUOp::Add64,
            rd: addr,
            rn: addr.to_reg(),
            rm: reg,
        });
    }
    for (reg, extendop) in addends32 {
        assert!(reg != stack_reg());
        ctx.emit(Inst::AluRRRExtend {
            alu_op: ALUOp::Add64,
            rd: addr,
            rn: addr.to_reg(),
            rm: reg,
            extendop,
        });
    }
    memarg
}
pub ( crate ) fn lower_address < C : LowerCtx < I = Inst > > ( ctx : & mut C , elem_ty : Type , roots : & [ InsnInput ] , offset : i32 , ) -> AMode { // TODO: support base_reg + scale * index_reg. For this, we would need to pattern-match shl or // mul instructions (Load/StoreComplex don't include scale factors). // Collect addends through an arbitrary tree of 32-to-64-bit sign/zero // extends and addition ops. We update these as we consume address // components, so they represent the remaining addends not yet handled. let ( mut addends64 , mut addends32 , args_offset ) = collect_address_addends ( ctx , roots ) ; let mut offset = args_offset + ( offset as i64 ) ; trace ! ( " " addends64 addends32 offset ) ; // First, decide what the `AMode` will be. Take one extendee and one 64-bit // reg, or two 64-bit regs, or a 64-bit reg and a 32-bit reg with extension, // or some other combination as appropriate. let memarg = if addends64 . len ( ) > 0 { if addends32 . len ( ) > 0 { let ( reg32 , extendop ) = addends32 . pop ( ) . unwrap ( ) ; let reg64 = addends64 . pop ( ) . unwrap ( ) ; AMode :: RegExtended ( reg64 , reg32 , extendop ) } else if offset > 0 && offset < 0x1000 { let reg64 = addends64 . pop ( ) . unwrap ( ) ; let off = offset ; offset = 0 ; AMode :: RegOffset ( reg64 , off , elem_ty ) } else if addends64 . len ( ) >= 2 { let reg1 = addends64 . pop ( ) . unwrap ( ) ; let reg2 = addends64 . pop ( ) . unwrap ( ) ; AMode :: RegReg ( reg1 , reg2 ) } else { let reg1 = addends64 . pop ( ) . unwrap ( ) ; AMode :: reg ( reg1 ) } } else /* addends64.len() == 0 */ { if addends32 . len ( ) > 0 { let tmp = ctx . alloc_tmp ( RegClass :: I64 , I64 ) ; let ( reg1 , extendop ) = addends32 . pop ( ) . unwrap ( ) ; let signed = match extendop { ExtendOp :: SXTW => true , ExtendOp :: UXTW => false , _ => unreachable ! ( ) , } ; ctx . emit ( Inst :: Extend { rd : tmp , rn : reg1 , signed , from_bits : 32 , to_bits : 64 , } ) ; if let Some ( ( reg2 , extendop ) ) = addends32 . pop ( ) { AMode :: RegExtended ( tmp . to_reg ( ) , reg2 , extendop ) } else { AMode :: reg ( tmp . to_reg ( ) ) } } else /* addends32.len() == 0 */ { let off_reg = ctx . alloc_tmp ( RegClass :: I64 , I64 ) ; lower_constant_u64 ( ctx , off_reg , offset as u64 ) ; offset = 0 ; AMode :: reg ( off_reg . to_reg ( ) ) } } ; // At this point, if we have any remaining components, we need to allocate a // temp, replace one of the registers in the AMode with the temp, and emit // instructions to add together the remaining components. Return immediately // if this is *not* the case. if offset == 0 && addends32 . len ( ) == 0 && addends64 . len ( ) == 0 { return memarg ; } // Allocate the temp and shoehorn it into the AMode. let addr = ctx . alloc_tmp ( RegClass :: I64 , I64 ) ; let ( reg , memarg ) = match memarg { AMode :: RegExtended ( r1 , r2 , extendop ) => { ( r1 , AMode :: RegExtended ( addr . to_reg ( ) , r2 , extendop ) ) } AMode :: RegOffset ( r , off , ty ) => ( r , AMode :: RegOffset ( addr . to_reg ( ) , off , ty ) ) , AMode :: RegReg ( r1 , r2 ) => ( r2 , AMode :: RegReg ( addr . to_reg ( ) , r1 ) ) , AMode :: UnsignedOffset ( r , imm ) => ( r , AMode :: UnsignedOffset ( addr . to_reg ( ) , imm ) ) , _ => unreachable ! ( ) , } ; // If there is any offset, load that first into `addr`, and add the `reg` // that we kicked out of the `AMode`; otherwise, start with that reg. if offset != 0 { // If we can fit offset or -offset in an imm12, use an add-imm // to combine the reg and offset. Otherwise, load value first then add. if let Some ( imm12 ) = Imm12 :: maybe_from_u64 ( offset as u64 ) { ctx . emit ( Inst :: AluRRImm12 { alu_op : ALUOp :: Add64 , rd : addr , rn : reg , imm12 , } ) ; } else if let Some ( imm12 ) = Imm12 :: maybe_from_u64 ( offset . wrapping_neg ( ) as u64 ) { ctx . emit ( Inst :: AluRRImm12 { alu_op : ALUOp :: Sub64 , rd : addr , rn : reg , imm12 , } ) ; } else { lower_constant_u64 ( ctx , addr , offset as u64 ) ; ctx . emit ( Inst :: AluRRR { alu_op : ALUOp :: Add64 , rd : addr , rn : addr . to_reg ( ) , rm : reg , } ) ; } } else { ctx . emit ( Inst :: gen_move ( addr , reg , I64 ) ) ; } // Now handle reg64 and reg32-extended components. for reg in addends64 { // If the register is the stack reg, we must move it to another reg // before adding it. let reg = if reg == stack_reg ( ) { let tmp = ctx . alloc_tmp ( RegClass :: I64 , I64 ) ; ctx . emit ( Inst :: gen_move ( tmp , stack_reg ( ) , I64 ) ) ; tmp . to_reg ( ) } else { reg } ; ctx . emit ( Inst :: AluRRR { alu_op : ALUOp :: Add64 , rd : addr , rn : addr . to_reg ( ) , rm : reg , } ) ; } for ( reg , extendop ) in addends32 { assert ! ( reg stack_reg ( ) ) ; ctx . emit ( Inst :: AluRRRExtend { alu_op : ALUOp :: Add64 , rd : addr , rn : addr . to_reg ( ) , rm : reg , extendop , } ) ; } memarg }
Lower the address of a load or store.
Lower the address of a load or store .
ctx
&mut C
elem_ty
Type
roots
&[InsnInput]
offset
i32
ctx
&mut C
elem_ty
Type
roots
&[InsnInput]
offset
i32