bool ArmVIXLAssembler::ShifterOperandCanHold(Opcode opcode,
uint32_t immediate,
vixl::aarch32::FlagsUpdate update_flags) { switch (opcode) { case ADD: case SUB: // Less than (or equal to) 12 bits can be done if we don't need to set condition codes. if (IsUint<12>(immediate) && update_flags != vixl::aarch32::SetFlags) { returntrue;
} return ShifterOperandCanAlwaysHold(immediate);
case MOV: // TODO: Support less than or equal to 12bits. return ShifterOperandCanAlwaysHold(immediate);
case MVN: default: return ShifterOperandCanAlwaysHold(immediate);
}
}
// TODO(VIXL): Implement this in VIXL.
int32_t ArmVIXLAssembler::GetAllowedLoadOffsetBits(LoadOperandType type) { switch (type) { case kLoadSignedByte: case kLoadSignedHalfword: case kLoadUnsignedHalfword: case kLoadUnsignedByte: case kLoadWord: // We can encode imm12 offset. return0xfff; case kLoadSWord: case kLoadDWord: case kLoadWordPair: // We can encode imm8:'00' offset. return0xff << 2;
}
}
// TODO(VIXL): Implement this in VIXL.
int32_t ArmVIXLAssembler::GetAllowedStoreOffsetBits(StoreOperandType type) { switch (type) { case kStoreHalfword: case kStoreByte: case kStoreWord: // We can encode imm12 offset. return0xfff; case kStoreSWord: case kStoreDWord: case kStoreWordPair: // We can encode imm8:'00' offset. return0xff << 2;
}
}
// TODO(VIXL): Implement this in VIXL. staticbool CanHoldLoadOffsetThumb(LoadOperandType type, int offset) { switch (type) { case kLoadSignedByte: case kLoadSignedHalfword: case kLoadUnsignedHalfword: case kLoadUnsignedByte: case kLoadWord: return IsAbsoluteUint<12>(offset); case kLoadSWord: case kLoadDWord: return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset); // VFP addressing mode. case kLoadWordPair: return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);
}
}
// TODO(VIXL): Implement this in VIXL. staticbool CanHoldStoreOffsetThumb(StoreOperandType type, int offset) { switch (type) { case kStoreHalfword: case kStoreByte: case kStoreWord: return IsAbsoluteUint<12>(offset); case kStoreSWord: case kStoreDWord: return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset); // VFP addressing mode. case kStoreWordPair: return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);
}
}
// Implementation note: this method must emit at most one instruction when // Address::CanHoldStoreOffsetThumb. // TODO(VIXL): Implement AdjustLoadStoreOffset logic in VIXL. void ArmVIXLAssembler::StoreToOffset(StoreOperandType type,
vixl32::Register reg,
vixl32::Register base,
int32_t offset) {
vixl32::Register tmp_reg;
UseScratchRegisterScope temps(&vixl_masm_);
if (!CanHoldStoreOffsetThumb(type, offset)) {
CHECK_NE(base.GetCode(), kIpCode); if ((reg.GetCode() != kIpCode) &&
(!vixl_masm_.GetScratchRegisterList()->IsEmpty()) &&
((type != kStoreWordPair) || (reg.GetCode() + 1 != kIpCode))) {
tmp_reg = temps.Acquire();
} else { // Be careful not to use ip twice (for `reg` (or `reg` + 1 in // the case of a word-pair store) and `base`) to build the // Address object used by the store instruction(s) below. // Instead, save R5 on the stack (or R6 if R5 is already used by // `base`), use it as secondary temporary register, and restore // it after the store instruction has been emitted.
tmp_reg = (base.GetCode() != 5) ? r5 : r6;
___ Push(tmp_reg); if (base.GetCode() == kSpCode) {
offset += kRegisterSize;
}
} // TODO: Implement indexed store (not available for STRD), inline AdjustLoadStoreOffset() // and in the "unsplittable" path get rid of the "add" by using the store indexed instead.
offset = AdjustLoadStoreOffset(GetAllowedStoreOffsetBits(type), tmp_reg, base, offset);
base = tmp_reg;
}
DCHECK(CanHoldStoreOffsetThumb(type, offset)); switch (type) { case kStoreByte:
___ Strb(reg, MemOperand(base, offset)); break; case kStoreHalfword:
___ Strh(reg, MemOperand(base, offset)); break; case kStoreWord:
___ Str(reg, MemOperand(base, offset)); break; case kStoreWordPair:
___ Strd(reg, vixl32::Register(reg.GetCode() + 1), MemOperand(base, offset)); break; default:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
} if ((tmp_reg.IsValid()) && (tmp_reg.GetCode() != kIpCode)) {
CHECK(tmp_reg.Is(r5) || tmp_reg.Is(r6)) << tmp_reg;
___ Pop(tmp_reg);
}
}
// Implementation note: this method must emit at most one instruction when // Address::CanHoldLoadOffsetThumb. // TODO(VIXL): Implement AdjustLoadStoreOffset logic in VIXL. void ArmVIXLAssembler::LoadFromOffset(LoadOperandType type,
vixl32::Register dest,
vixl32::Register base,
int32_t offset) { if (!CanHoldLoadOffsetThumb(type, offset)) {
CHECK(!base.Is(ip)); // Inlined AdjustLoadStoreOffset() allows us to pull a few more tricks.
int32_t allowed_offset_bits = GetAllowedLoadOffsetBits(type);
DCHECK_NE(offset & ~allowed_offset_bits, 0);
int32_t add_to_base, offset_for_load; if (CanSplitLoadStoreOffset(allowed_offset_bits, offset, &add_to_base, &offset_for_load)) { // Use reg for the adjusted base. If it's low reg, we may end up using 16-bit load.
AddConstant(dest, base, add_to_base);
base = dest;
offset = offset_for_load;
} else {
UseScratchRegisterScope temps(&vixl_masm_);
vixl32::Register temp = (dest.Is(base)) ? temps.Acquire() : dest;
LoadImmediate(temp, offset); // TODO: Implement indexed load (not available for LDRD) and use it here to avoid the ADD. // Use reg for the adjusted base. If it's low reg, we may end up using 16-bit load.
___ Add(dest, dest, (dest.Is(base)) ? temp : base);
base = dest;
offset = 0;
}
}
DCHECK(CanHoldLoadOffsetThumb(type, offset)); switch (type) { case kLoadSignedByte:
___ Ldrsb(dest, MemOperand(base, offset)); break; case kLoadUnsignedByte:
___ Ldrb(dest, MemOperand(base, offset)); break; case kLoadSignedHalfword:
___ Ldrsh(dest, MemOperand(base, offset)); break; case kLoadUnsignedHalfword:
___ Ldrh(dest, MemOperand(base, offset)); break; case kLoadWord:
CHECK(!dest.IsSP());
___ Ldr(dest, MemOperand(base, offset)); break; case kLoadWordPair:
___ Ldrd(dest, vixl32::Register(dest.GetCode() + 1), MemOperand(base, offset)); break; default:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
}
}
// Prefer Str to Add/Stm in ArmVIXLAssembler::StoreRegisterList and // ArmVIXLAssembler::LoadRegisterList where this generates less code (size). static constexpr int kRegListThreshold = 4;
void ArmVIXLAssembler::StoreRegisterList(RegList regs, size_t stack_offset) { int number_of_regs = POPCOUNT(static_cast<uint32_t>(regs)); if (number_of_regs != 0) { if (number_of_regs > kRegListThreshold) {
UseScratchRegisterScope temps(GetVIXLAssembler());
vixl32::Register base = sp; if (stack_offset != 0) {
base = temps.Acquire();
DCHECK_EQ(regs & (1u << base.GetCode()), 0u);
___ Add(base, sp, Operand::From(stack_offset));
}
___ Stm(base, NO_WRITE_BACK, RegisterList(regs));
} else { for (uint32_t i : LowToHighBits(static_cast<uint32_t>(regs))) {
___ Str(vixl32::Register(i), MemOperand(sp, stack_offset));
stack_offset += kRegSizeInBytes;
}
}
}
}
void ArmVIXLAssembler::LoadRegisterList(RegList regs, size_t stack_offset) { int number_of_regs = POPCOUNT(static_cast<uint32_t>(regs)); if (number_of_regs != 0) { if (number_of_regs > kRegListThreshold) {
UseScratchRegisterScope temps(GetVIXLAssembler());
vixl32::Register base = sp; if (stack_offset != 0) {
base = temps.Acquire();
___ Add(base, sp, Operand::From(stack_offset));
}
___ Ldm(base, NO_WRITE_BACK, RegisterList(regs));
} else { for (uint32_t i : LowToHighBits(static_cast<uint32_t>(regs))) {
___ Ldr(vixl32::Register(i), MemOperand(sp, stack_offset));
stack_offset += kRegSizeInBytes;
}
}
}
}
// TODO(VIXL): think about using adds which updates flags where possible. void ArmVIXLAssembler::AddConstant(vixl32::Register rd,
vixl32::Register rn,
int32_t value) {
DCHECK(vixl_masm_.OutsideITBlock()); // TODO(VIXL): implement this optimization in VIXL. if (value == 0) { if (!rd.Is(rn)) {
___ Mov(rd, rn);
} return;
}
___ Add(rd, rn, value);
}
// Inside IT block we must use assembler, macroassembler instructions are not permitted. void ArmVIXLAssembler::AddConstantInIt(vixl32::Register rd,
vixl32::Register rn,
int32_t value,
vixl32::Condition cond) {
DCHECK(vixl_masm_.InITBlock()); if (value == 0) {
___ mov(cond, rd, rn);
} else {
___ add(cond, rd, rn, value);
}
}
void ArmVIXLMacroAssembler::CompareAndBranchIfZero(vixl32::Register rn,
vixl32::Label* label, bool is_far_target) { if (!is_far_target && rn.IsLow() && !label->IsBound()) { // In T32, Cbz/Cbnz instructions have following limitations: // - There are only 7 bits (i:imm5:0) to encode branch target address (cannot be far target). // - Only low registers (i.e R0 .. R7) can be encoded. // - Only forward branches (unbound labels) are supported.
Cbz(rn, label); return;
}
Cmp(rn, 0);
B(eq, label, is_far_target);
}
void ArmVIXLMacroAssembler::B(vixl32::Label* label) { if (!label->IsBound()) { // Try to use a 16-bit encoding of the B instruction.
DCHECK(OutsideITBlock());
BPreferNear(label); return;
}
MacroAssembler::B(label);
}
void ArmVIXLMacroAssembler::B(vixl32::Condition cond, vixl32::Label* label, bool is_far_target) { if (!label->IsBound() && !is_far_target) { // Try to use a 16-bit encoding of the B instruction.
DCHECK(OutsideITBlock());
BPreferNear(cond, label); return;
}
MacroAssembler::B(cond, label);
}
} // namespace arm
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.