diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/Android.mk | 2 | ||||
-rw-r--r-- | compiler/jni/quick/jni_compiler.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 4 | ||||
-rw-r--r-- | compiler/trampolines/trampoline_compiler.cc | 4 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm.cc | 1600 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm.h | 715 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 1423 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 352 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 2363 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 685 | ||||
-rw-r--r-- | compiler/utils/arm/constants_arm.h | 4 | ||||
-rw-r--r-- | compiler/utils/assembler.cc | 6 | ||||
-rw-r--r-- | compiler/utils/assembler.h | 15 | ||||
-rw-r--r-- | compiler/utils/assembler_thumb_test.cc | 1225 | ||||
-rw-r--r-- | compiler/utils/assembler_thumb_test_expected.cc.inc | 4788 |
15 files changed, 11537 insertions, 1653 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index f297213..88fdee0 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -93,6 +93,8 @@ LIBART_COMPILER_SRC_FILES := \ utils/arena_allocator.cc \ utils/arena_bit_vector.cc \ utils/arm/assembler_arm.cc \ + utils/arm/assembler_arm32.cc \ + utils/arm/assembler_thumb2.cc \ utils/arm/managed_register_arm.cc \ utils/arm64/assembler_arm64.cc \ utils/arm64/managed_register_arm64.cc \ diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 7664a7f..3bbb723 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -17,6 +17,7 @@ #include <algorithm> #include <memory> #include <vector> +#include <fstream> #include "base/logging.h" #include "base/macros.h" @@ -61,9 +62,6 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver, const bool is_synchronized = (access_flags & kAccSynchronized) != 0; const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); InstructionSet instruction_set = driver->GetInstructionSet(); - if (instruction_set == kThumb2) { - instruction_set = kArm; - } const bool is_64_bit_target = Is64BitInstructionSet(instruction_set); // Calling conventions used to iterate over parameters to method std::unique_ptr<JniCallingConvention> main_jni_conv( diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 423b13e..c945a06 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -19,7 +19,7 @@ #include "code_generator.h" #include "nodes.h" -#include "utils/arm/assembler_arm.h" +#include "utils/arm/assembler_arm32.h" namespace art { namespace arm { @@ -152,7 +152,7 @@ class CodeGeneratorARM : public CodeGenerator { LocationsBuilderARM location_builder_; InstructionCodeGeneratorARM instruction_visitor_; - ArmAssembler assembler_; + Arm32Assembler assembler_; DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM); }; diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc index 24378b4..ac84d6a 100644 --- a/compiler/trampolines/trampoline_compiler.cc +++ b/compiler/trampolines/trampoline_compiler.cc @@ -30,6 +30,10 @@ namespace art { namespace arm { static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi, ThreadOffset<4> offset) { + // NOTE: the assembler used here is ARM, not Thumb. This is because the address + // returned by this function is a pointer and for thumb we would have to set the + // bottom bit. It doesn't matter since the instructions generated are the same + // size anyway. std::unique_ptr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm))); switch (abi) { diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc index 64685c1..b607a1d 100644 --- a/compiler/utils/arm/assembler_arm.cc +++ b/compiler/utils/arm/assembler_arm.cc @@ -25,66 +25,16 @@ namespace art { namespace arm { -// Instruction encoding bits. -enum { - H = 1 << 5, // halfword (or byte) - L = 1 << 20, // load (or store) - S = 1 << 20, // set condition code (or leave unchanged) - W = 1 << 21, // writeback base register (or leave unchanged) - A = 1 << 21, // accumulate in multiply instruction (or not) - B = 1 << 22, // unsigned byte (or word) - N = 1 << 22, // long (or short) - U = 1 << 23, // positive (or negative) offset/index - P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing) - I = 1 << 25, // immediate shifter operand (or not) - - B0 = 1, - B1 = 1 << 1, - B2 = 1 << 2, - B3 = 1 << 3, - B4 = 1 << 4, - B5 = 1 << 5, - B6 = 1 << 6, - B7 = 1 << 7, - B8 = 1 << 8, - B9 = 1 << 9, - B10 = 1 << 10, - B11 = 1 << 11, - B12 = 1 << 12, - B16 = 1 << 16, - B17 = 1 << 17, - B18 = 1 << 18, - B19 = 1 << 19, - B20 = 1 << 20, - B21 = 1 << 21, - B22 = 1 << 22, - B23 = 1 << 23, - B24 = 1 << 24, - B25 = 1 << 25, - B26 = 1 << 26, - B27 = 1 << 27, - - // Instruction bit masks. - RdMask = 15 << 12, // in str instruction - CondMask = 15 << 28, - CoprocessorMask = 15 << 8, - OpCodeMask = 15 << 21, // in data-processing instructions - Imm24Mask = (1 << 24) - 1, - Off12Mask = (1 << 12) - 1, - - // ldrex/strex register field encodings. - kLdExRnShift = 16, - kLdExRtShift = 12, - kStrExRnShift = 16, - kStrExRdShift = 12, - kStrExRtShift = 0, -}; - - -static const char* kRegisterNames[] = { +const char* kRegisterNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc" }; + +const char* kConditionNames[] = { + "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", + "LE", "AL", +}; + std::ostream& operator<<(std::ostream& os, const Register& rhs) { if (rhs >= R0 && rhs <= PC) { os << kRegisterNames[rhs]; @@ -114,11 +64,6 @@ std::ostream& operator<<(std::ostream& os, const DRegister& rhs) { return os; } - -static const char* kConditionNames[] = { - "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", - "LE", "AL", -}; std::ostream& operator<<(std::ostream& os, const Condition& rhs) { if (rhs >= EQ && rhs <= AL) { os << kConditionNames[rhs]; @@ -128,1084 +73,218 @@ std::ostream& operator<<(std::ostream& os, const Condition& rhs) { return os; } -void ArmAssembler::Emit(int32_t value) { - AssemblerBuffer::EnsureCapacity ensured(&buffer_); - buffer_.Emit<int32_t>(value); -} - - -void ArmAssembler::EmitType01(Condition cond, - int type, - Opcode opcode, - int set_cc, - Register rn, - Register rd, - ShifterOperand so) { - CHECK_NE(rd, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | - type << kTypeShift | - static_cast<int32_t>(opcode) << kOpcodeShift | - set_cc << kSShift | - static_cast<int32_t>(rn) << kRnShift | - static_cast<int32_t>(rd) << kRdShift | - so.encoding(); - Emit(encoding); -} - - -void ArmAssembler::EmitType5(Condition cond, int offset, bool link) { - CHECK_NE(cond, kNoCondition); - int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | - 5 << kTypeShift | - (link ? 1 : 0) << kLinkShift; - Emit(ArmAssembler::EncodeBranchOffset(offset, encoding)); -} - - -void ArmAssembler::EmitMemOp(Condition cond, - bool load, - bool byte, - Register rd, - Address ad) { - CHECK_NE(rd, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B26 | - (load ? L : 0) | - (byte ? B : 0) | - (static_cast<int32_t>(rd) << kRdShift) | - ad.encoding(); - Emit(encoding); -} - - -void ArmAssembler::EmitMemOpAddressMode3(Condition cond, - int32_t mode, - Register rd, - Address ad) { - CHECK_NE(rd, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B22 | - mode | - (static_cast<int32_t>(rd) << kRdShift) | - ad.encoding3(); - Emit(encoding); -} - - -void ArmAssembler::EmitMultiMemOp(Condition cond, - BlockAddressMode am, - bool load, - Register base, - RegList regs) { - CHECK_NE(base, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | - am | - (load ? L : 0) | - (static_cast<int32_t>(base) << kRnShift) | - regs; - Emit(encoding); -} - - -void ArmAssembler::EmitShiftImmediate(Condition cond, - Shift opcode, - Register rd, - Register rm, - ShifterOperand so) { - CHECK_NE(cond, kNoCondition); - CHECK_EQ(so.type(), 1U); - int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | - static_cast<int32_t>(MOV) << kOpcodeShift | - static_cast<int32_t>(rd) << kRdShift | - so.encoding() << kShiftImmShift | - static_cast<int32_t>(opcode) << kShiftShift | - static_cast<int32_t>(rm); - Emit(encoding); -} - - -void ArmAssembler::EmitShiftRegister(Condition cond, - Shift opcode, - Register rd, - Register rm, - ShifterOperand so) { - CHECK_NE(cond, kNoCondition); - CHECK_EQ(so.type(), 0U); - int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | - static_cast<int32_t>(MOV) << kOpcodeShift | - static_cast<int32_t>(rd) << kRdShift | - so.encoding() << kShiftRegisterShift | - static_cast<int32_t>(opcode) << kShiftShift | - B4 | - static_cast<int32_t>(rm); - Emit(encoding); -} - - -void ArmAssembler::EmitBranch(Condition cond, Label* label, bool link) { - if (label->IsBound()) { - EmitType5(cond, label->Position() - buffer_.Size(), link); - } else { - int position = buffer_.Size(); - // Use the offset field of the branch instruction for linking the sites. - EmitType5(cond, label->position_, link); - label->LinkTo(position); - } -} - -void ArmAssembler::and_(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), AND, 0, rn, rd, so); -} - - -void ArmAssembler::eor(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), EOR, 0, rn, rd, so); -} - - -void ArmAssembler::sub(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), SUB, 0, rn, rd, so); -} - -void ArmAssembler::rsb(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), RSB, 0, rn, rd, so); -} - -void ArmAssembler::rsbs(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), RSB, 1, rn, rd, so); -} - - -void ArmAssembler::add(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), ADD, 0, rn, rd, so); -} - - -void ArmAssembler::adds(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), ADD, 1, rn, rd, so); -} - - -void ArmAssembler::subs(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), SUB, 1, rn, rd, so); -} - - -void ArmAssembler::adc(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), ADC, 0, rn, rd, so); -} - - -void ArmAssembler::sbc(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), SBC, 0, rn, rd, so); -} - - -void ArmAssembler::rsc(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), RSC, 0, rn, rd, so); -} - - -void ArmAssembler::tst(Register rn, ShifterOperand so, Condition cond) { - CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker. - EmitType01(cond, so.type(), TST, 1, rn, R0, so); -} - - -void ArmAssembler::teq(Register rn, ShifterOperand so, Condition cond) { - CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker. - EmitType01(cond, so.type(), TEQ, 1, rn, R0, so); -} - - -void ArmAssembler::cmp(Register rn, ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), CMP, 1, rn, R0, so); -} - - -void ArmAssembler::cmn(Register rn, ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), CMN, 1, rn, R0, so); -} - - -void ArmAssembler::orr(Register rd, Register rn, - ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), ORR, 0, rn, rd, so); -} - - -void ArmAssembler::orrs(Register rd, Register rn, - ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), ORR, 1, rn, rd, so); -} - - -void ArmAssembler::mov(Register rd, ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), MOV, 0, R0, rd, so); -} - - -void ArmAssembler::movs(Register rd, ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), MOV, 1, R0, rd, so); -} - - -void ArmAssembler::bic(Register rd, Register rn, ShifterOperand so, - Condition cond) { - EmitType01(cond, so.type(), BIC, 0, rn, rd, so); -} - - -void ArmAssembler::mvn(Register rd, ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), MVN, 0, R0, rd, so); -} - - -void ArmAssembler::mvns(Register rd, ShifterOperand so, Condition cond) { - EmitType01(cond, so.type(), MVN, 1, R0, rd, so); -} - - -void ArmAssembler::clz(Register rd, Register rm, Condition cond) { - CHECK_NE(rd, kNoRegister); - CHECK_NE(rm, kNoRegister); - CHECK_NE(cond, kNoCondition); - CHECK_NE(rd, PC); - CHECK_NE(rm, PC); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B24 | B22 | B21 | (0xf << 16) | - (static_cast<int32_t>(rd) << kRdShift) | - (0xf << 8) | B4 | static_cast<int32_t>(rm); - Emit(encoding); -} - - -void ArmAssembler::movw(Register rd, uint16_t imm16, Condition cond) { - CHECK_NE(cond, kNoCondition); - int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | - B25 | B24 | ((imm16 >> 12) << 16) | - static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff); - Emit(encoding); -} - - -void ArmAssembler::movt(Register rd, uint16_t imm16, Condition cond) { - CHECK_NE(cond, kNoCondition); - int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | - B25 | B24 | B22 | ((imm16 >> 12) << 16) | - static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff); - Emit(encoding); -} - - -void ArmAssembler::EmitMulOp(Condition cond, int32_t opcode, - Register rd, Register rn, - Register rm, Register rs) { - CHECK_NE(rd, kNoRegister); - CHECK_NE(rn, kNoRegister); - CHECK_NE(rm, kNoRegister); - CHECK_NE(rs, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = opcode | - (static_cast<int32_t>(cond) << kConditionShift) | - (static_cast<int32_t>(rn) << kRnShift) | - (static_cast<int32_t>(rd) << kRdShift) | - (static_cast<int32_t>(rs) << kRsShift) | - B7 | B4 | - (static_cast<int32_t>(rm) << kRmShift); - Emit(encoding); -} - - -void ArmAssembler::mul(Register rd, Register rn, Register rm, Condition cond) { - // Assembler registers rd, rn, rm are encoded as rn, rm, rs. - EmitMulOp(cond, 0, R0, rd, rn, rm); -} - - -void ArmAssembler::mla(Register rd, Register rn, Register rm, Register ra, - Condition cond) { - // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. - EmitMulOp(cond, B21, ra, rd, rn, rm); -} - - -void ArmAssembler::mls(Register rd, Register rn, Register rm, Register ra, - Condition cond) { - // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. - EmitMulOp(cond, B22 | B21, ra, rd, rn, rm); -} - - -void ArmAssembler::umull(Register rd_lo, Register rd_hi, Register rn, - Register rm, Condition cond) { - // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. - EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm); -} - - -void ArmAssembler::ldr(Register rd, Address ad, Condition cond) { - EmitMemOp(cond, true, false, rd, ad); -} - - -void ArmAssembler::str(Register rd, Address ad, Condition cond) { - EmitMemOp(cond, false, false, rd, ad); -} - - -void ArmAssembler::ldrb(Register rd, Address ad, Condition cond) { - EmitMemOp(cond, true, true, rd, ad); -} - - -void ArmAssembler::strb(Register rd, Address ad, Condition cond) { - EmitMemOp(cond, false, true, rd, ad); -} - - -void ArmAssembler::ldrh(Register rd, Address ad, Condition cond) { - EmitMemOpAddressMode3(cond, L | B7 | H | B4, rd, ad); -} -void ArmAssembler::strh(Register rd, Address ad, Condition cond) { - EmitMemOpAddressMode3(cond, B7 | H | B4, rd, ad); -} - - -void ArmAssembler::ldrsb(Register rd, Address ad, Condition cond) { - EmitMemOpAddressMode3(cond, L | B7 | B6 | B4, rd, ad); -} - - -void ArmAssembler::ldrsh(Register rd, Address ad, Condition cond) { - EmitMemOpAddressMode3(cond, L | B7 | B6 | H | B4, rd, ad); -} - - -void ArmAssembler::ldrd(Register rd, Address ad, Condition cond) { - CHECK_EQ(rd % 2, 0); - EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, ad); -} - - -void ArmAssembler::strd(Register rd, Address ad, Condition cond) { - CHECK_EQ(rd % 2, 0); - EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, ad); -} - - -void ArmAssembler::ldm(BlockAddressMode am, - Register base, - RegList regs, - Condition cond) { - EmitMultiMemOp(cond, am, true, base, regs); -} - - -void ArmAssembler::stm(BlockAddressMode am, - Register base, - RegList regs, - Condition cond) { - EmitMultiMemOp(cond, am, false, base, regs); -} - - -void ArmAssembler::ldrex(Register rt, Register rn, Condition cond) { - CHECK_NE(rn, kNoRegister); - CHECK_NE(rt, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B24 | - B23 | - L | - (static_cast<int32_t>(rn) << kLdExRnShift) | - (static_cast<int32_t>(rt) << kLdExRtShift) | - B11 | B10 | B9 | B8 | B7 | B4 | B3 | B2 | B1 | B0; - Emit(encoding); -} - - -void ArmAssembler::strex(Register rd, - Register rt, - Register rn, - Condition cond) { - CHECK_NE(rn, kNoRegister); - CHECK_NE(rd, kNoRegister); - CHECK_NE(rt, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B24 | - B23 | - (static_cast<int32_t>(rn) << kStrExRnShift) | - (static_cast<int32_t>(rd) << kStrExRdShift) | - B11 | B10 | B9 | B8 | B7 | B4 | - (static_cast<int32_t>(rt) << kStrExRtShift); - Emit(encoding); -} - - -void ArmAssembler::clrex() { - int32_t encoding = (kSpecialCondition << kConditionShift) | - B26 | B24 | B22 | B21 | B20 | (0xff << 12) | B4 | 0xf; - Emit(encoding); -} - - -void ArmAssembler::nop(Condition cond) { - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B25 | B24 | B21 | (0xf << 12); - Emit(encoding); -} - - -void ArmAssembler::vmovsr(SRegister sn, Register rt, Condition cond) { - CHECK_NE(sn, kNoSRegister); - CHECK_NE(rt, kNoRegister); - CHECK_NE(rt, SP); - CHECK_NE(rt, PC); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B25 | - ((static_cast<int32_t>(sn) >> 1)*B16) | - (static_cast<int32_t>(rt)*B12) | B11 | B9 | - ((static_cast<int32_t>(sn) & 1)*B7) | B4; - Emit(encoding); -} - - -void ArmAssembler::vmovrs(Register rt, SRegister sn, Condition cond) { - CHECK_NE(sn, kNoSRegister); - CHECK_NE(rt, kNoRegister); - CHECK_NE(rt, SP); - CHECK_NE(rt, PC); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B25 | B20 | - ((static_cast<int32_t>(sn) >> 1)*B16) | - (static_cast<int32_t>(rt)*B12) | B11 | B9 | - ((static_cast<int32_t>(sn) & 1)*B7) | B4; - Emit(encoding); -} - - -void ArmAssembler::vmovsrr(SRegister sm, Register rt, Register rt2, - Condition cond) { - CHECK_NE(sm, kNoSRegister); - CHECK_NE(sm, S31); - CHECK_NE(rt, kNoRegister); - CHECK_NE(rt, SP); - CHECK_NE(rt, PC); - CHECK_NE(rt2, kNoRegister); - CHECK_NE(rt2, SP); - CHECK_NE(rt2, PC); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B22 | - (static_cast<int32_t>(rt2)*B16) | - (static_cast<int32_t>(rt)*B12) | B11 | B9 | - ((static_cast<int32_t>(sm) & 1)*B5) | B4 | - (static_cast<int32_t>(sm) >> 1); - Emit(encoding); -} - - -void ArmAssembler::vmovrrs(Register rt, Register rt2, SRegister sm, - Condition cond) { - CHECK_NE(sm, kNoSRegister); - CHECK_NE(sm, S31); - CHECK_NE(rt, kNoRegister); - CHECK_NE(rt, SP); - CHECK_NE(rt, PC); - CHECK_NE(rt2, kNoRegister); - CHECK_NE(rt2, SP); - CHECK_NE(rt2, PC); - CHECK_NE(rt, rt2); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B22 | B20 | - (static_cast<int32_t>(rt2)*B16) | - (static_cast<int32_t>(rt)*B12) | B11 | B9 | - ((static_cast<int32_t>(sm) & 1)*B5) | B4 | - (static_cast<int32_t>(sm) >> 1); - Emit(encoding); -} - - -void ArmAssembler::vmovdrr(DRegister dm, Register rt, Register rt2, - Condition cond) { - CHECK_NE(dm, kNoDRegister); - CHECK_NE(rt, kNoRegister); - CHECK_NE(rt, SP); - CHECK_NE(rt, PC); - CHECK_NE(rt2, kNoRegister); - CHECK_NE(rt2, SP); - CHECK_NE(rt2, PC); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B22 | - (static_cast<int32_t>(rt2)*B16) | - (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 | - ((static_cast<int32_t>(dm) >> 4)*B5) | B4 | - (static_cast<int32_t>(dm) & 0xf); - Emit(encoding); -} - - -void ArmAssembler::vmovrrd(Register rt, Register rt2, DRegister dm, - Condition cond) { - CHECK_NE(dm, kNoDRegister); - CHECK_NE(rt, kNoRegister); - CHECK_NE(rt, SP); - CHECK_NE(rt, PC); - CHECK_NE(rt2, kNoRegister); - CHECK_NE(rt2, SP); - CHECK_NE(rt2, PC); - CHECK_NE(rt, rt2); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B22 | B20 | - (static_cast<int32_t>(rt2)*B16) | - (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 | - ((static_cast<int32_t>(dm) >> 4)*B5) | B4 | - (static_cast<int32_t>(dm) & 0xf); - Emit(encoding); -} - - -void ArmAssembler::vldrs(SRegister sd, Address ad, Condition cond) { - CHECK_NE(sd, kNoSRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B24 | B20 | - ((static_cast<int32_t>(sd) & 1)*B22) | - ((static_cast<int32_t>(sd) >> 1)*B12) | - B11 | B9 | ad.vencoding(); - Emit(encoding); -} - - -void ArmAssembler::vstrs(SRegister sd, Address ad, Condition cond) { - CHECK_NE(static_cast<Register>(ad.encoding_ & (0xf << kRnShift)), PC); - CHECK_NE(sd, kNoSRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B24 | - ((static_cast<int32_t>(sd) & 1)*B22) | - ((static_cast<int32_t>(sd) >> 1)*B12) | - B11 | B9 | ad.vencoding(); - Emit(encoding); -} - - -void ArmAssembler::vldrd(DRegister dd, Address ad, Condition cond) { - CHECK_NE(dd, kNoDRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B24 | B20 | - ((static_cast<int32_t>(dd) >> 4)*B22) | - ((static_cast<int32_t>(dd) & 0xf)*B12) | - B11 | B9 | B8 | ad.vencoding(); - Emit(encoding); -} - - -void ArmAssembler::vstrd(DRegister dd, Address ad, Condition cond) { - CHECK_NE(static_cast<Register>(ad.encoding_ & (0xf << kRnShift)), PC); - CHECK_NE(dd, kNoDRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B24 | - ((static_cast<int32_t>(dd) >> 4)*B22) | - ((static_cast<int32_t>(dd) & 0xf)*B12) | - B11 | B9 | B8 | ad.vencoding(); - Emit(encoding); -} - - -void ArmAssembler::EmitVFPsss(Condition cond, int32_t opcode, - SRegister sd, SRegister sn, SRegister sm) { - CHECK_NE(sd, kNoSRegister); - CHECK_NE(sn, kNoSRegister); - CHECK_NE(sm, kNoSRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B25 | B11 | B9 | opcode | - ((static_cast<int32_t>(sd) & 1)*B22) | - ((static_cast<int32_t>(sn) >> 1)*B16) | - ((static_cast<int32_t>(sd) >> 1)*B12) | - ((static_cast<int32_t>(sn) & 1)*B7) | - ((static_cast<int32_t>(sm) & 1)*B5) | - (static_cast<int32_t>(sm) >> 1); - Emit(encoding); -} - - -void ArmAssembler::EmitVFPddd(Condition cond, int32_t opcode, - DRegister dd, DRegister dn, DRegister dm) { - CHECK_NE(dd, kNoDRegister); - CHECK_NE(dn, kNoDRegister); - CHECK_NE(dm, kNoDRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B25 | B11 | B9 | B8 | opcode | - ((static_cast<int32_t>(dd) >> 4)*B22) | - ((static_cast<int32_t>(dn) & 0xf)*B16) | - ((static_cast<int32_t>(dd) & 0xf)*B12) | - ((static_cast<int32_t>(dn) >> 4)*B7) | - ((static_cast<int32_t>(dm) >> 4)*B5) | - (static_cast<int32_t>(dm) & 0xf); - Emit(encoding); -} - - -void ArmAssembler::vmovs(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm); -} - - -void ArmAssembler::vmovd(DRegister dd, DRegister dm, Condition cond) { - EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm); -} - - -bool ArmAssembler::vmovs(SRegister sd, float s_imm, Condition cond) { - uint32_t imm32 = bit_cast<uint32_t, float>(s_imm); - if (((imm32 & ((1 << 19) - 1)) == 0) && - ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) || - (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) { - uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) | - ((imm32 >> 19) & ((1 << 6) -1)); - EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf), - sd, S0, S0); - return true; - } - return false; -} - - -bool ArmAssembler::vmovd(DRegister dd, double d_imm, Condition cond) { - uint64_t imm64 = bit_cast<uint64_t, double>(d_imm); - if (((imm64 & ((1LL << 48) - 1)) == 0) && - ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) || - (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) { - uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) | - ((imm64 >> 48) & ((1 << 6) -1)); - EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf), - dd, D0, D0); - return true; +uint32_t ShifterOperand::encodingArm() const { + CHECK(is_valid()); + switch (type_) { + case kImmediate: + if (is_rotate_) { + return (rotate_ << kRotateShift) | (immed_ << kImmed8Shift); + } else { + return immed_; + } + break; + case kRegister: + if (is_shift_) { + // Shifted immediate or register. + if (rs_ == kNoRegister) { + // Immediate shift. + return immed_ << kShiftImmShift | + static_cast<uint32_t>(shift_) << kShiftShift | + static_cast<uint32_t>(rm_); + } else { + // Register shift. + return static_cast<uint32_t>(rs_) << kShiftRegisterShift | + static_cast<uint32_t>(shift_) << kShiftShift | (1 << 4) | + static_cast<uint32_t>(rm_); + } + } else { + // Simple register + return static_cast<uint32_t>(rm_); + } + break; + default: + // Can't get here. + LOG(FATAL) << "Invalid shifter operand for ARM"; + return 0; } - return false; -} - - -void ArmAssembler::vadds(SRegister sd, SRegister sn, SRegister sm, - Condition cond) { - EmitVFPsss(cond, B21 | B20, sd, sn, sm); -} - - -void ArmAssembler::vaddd(DRegister dd, DRegister dn, DRegister dm, - Condition cond) { - EmitVFPddd(cond, B21 | B20, dd, dn, dm); -} - - -void ArmAssembler::vsubs(SRegister sd, SRegister sn, SRegister sm, - Condition cond) { - EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm); -} - - -void ArmAssembler::vsubd(DRegister dd, DRegister dn, DRegister dm, - Condition cond) { - EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm); -} - - -void ArmAssembler::vmuls(SRegister sd, SRegister sn, SRegister sm, - Condition cond) { - EmitVFPsss(cond, B21, sd, sn, sm); -} - - -void ArmAssembler::vmuld(DRegister dd, DRegister dn, DRegister dm, - Condition cond) { - EmitVFPddd(cond, B21, dd, dn, dm); -} - - -void ArmAssembler::vmlas(SRegister sd, SRegister sn, SRegister sm, - Condition cond) { - EmitVFPsss(cond, 0, sd, sn, sm); -} - - -void ArmAssembler::vmlad(DRegister dd, DRegister dn, DRegister dm, - Condition cond) { - EmitVFPddd(cond, 0, dd, dn, dm); -} - - -void ArmAssembler::vmlss(SRegister sd, SRegister sn, SRegister sm, - Condition cond) { - EmitVFPsss(cond, B6, sd, sn, sm); -} - - -void ArmAssembler::vmlsd(DRegister dd, DRegister dn, DRegister dm, - Condition cond) { - EmitVFPddd(cond, B6, dd, dn, dm); -} - - -void ArmAssembler::vdivs(SRegister sd, SRegister sn, SRegister sm, - Condition cond) { - EmitVFPsss(cond, B23, sd, sn, sm); -} - - -void ArmAssembler::vdivd(DRegister dd, DRegister dn, DRegister dm, - Condition cond) { - EmitVFPddd(cond, B23, dd, dn, dm); -} - - -void ArmAssembler::vabss(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm); -} - - -void ArmAssembler::vabsd(DRegister dd, DRegister dm, Condition cond) { - EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm); -} - - -void ArmAssembler::vnegs(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm); -} - - -void ArmAssembler::vnegd(DRegister dd, DRegister dm, Condition cond) { - EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm); -} - - -void ArmAssembler::vsqrts(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm); -} - -void ArmAssembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) { - EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm); -} - - -void ArmAssembler::EmitVFPsd(Condition cond, int32_t opcode, - SRegister sd, DRegister dm) { - CHECK_NE(sd, kNoSRegister); - CHECK_NE(dm, kNoDRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B25 | B11 | B9 | opcode | - ((static_cast<int32_t>(sd) & 1)*B22) | - ((static_cast<int32_t>(sd) >> 1)*B12) | - ((static_cast<int32_t>(dm) >> 4)*B5) | - (static_cast<int32_t>(dm) & 0xf); - Emit(encoding); -} - - -void ArmAssembler::EmitVFPds(Condition cond, int32_t opcode, - DRegister dd, SRegister sm) { - CHECK_NE(dd, kNoDRegister); - CHECK_NE(sm, kNoSRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B25 | B11 | B9 | opcode | - ((static_cast<int32_t>(dd) >> 4)*B22) | - ((static_cast<int32_t>(dd) & 0xf)*B12) | - ((static_cast<int32_t>(sm) & 1)*B5) | - (static_cast<int32_t>(sm) >> 1); - Emit(encoding); -} - - -void ArmAssembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) { - EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm); -} - - -void ArmAssembler::vcvtds(DRegister dd, SRegister sm, Condition cond) { - EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm); -} - - -void ArmAssembler::vcvtis(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm); -} - - -void ArmAssembler::vcvtid(SRegister sd, DRegister dm, Condition cond) { - EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm); -} - - -void ArmAssembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm); -} - - -void ArmAssembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) { - EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm); -} - - -void ArmAssembler::vcvtus(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm); -} - - -void ArmAssembler::vcvtud(SRegister sd, DRegister dm, Condition cond) { - EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm); -} - - -void ArmAssembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm); -} - - -void ArmAssembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) { - EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm); -} - - -void ArmAssembler::vcmps(SRegister sd, SRegister sm, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm); -} - - -void ArmAssembler::vcmpd(DRegister dd, DRegister dm, Condition cond) { - EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm); -} - - -void ArmAssembler::vcmpsz(SRegister sd, Condition cond) { - EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0); -} - - -void ArmAssembler::vcmpdz(DRegister dd, Condition cond) { - EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0); -} - - -void ArmAssembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 | - (static_cast<int32_t>(PC)*B12) | - B11 | B9 | B4; - Emit(encoding); -} - - -void ArmAssembler::svc(uint32_t imm24) { - CHECK(IsUint(24, imm24)) << imm24; - int32_t encoding = (AL << kConditionShift) | B27 | B26 | B25 | B24 | imm24; - Emit(encoding); -} - - -void ArmAssembler::bkpt(uint16_t imm16) { - int32_t encoding = (AL << kConditionShift) | B24 | B21 | - ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); - Emit(encoding); -} - - -void ArmAssembler::b(Label* label, Condition cond) { - EmitBranch(cond, label, false); -} - - -void ArmAssembler::bl(Label* label, Condition cond) { - EmitBranch(cond, label, true); -} - - -void ArmAssembler::blx(Register rm, Condition cond) { - CHECK_NE(rm, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B24 | B21 | (0xfff << 8) | B5 | B4 | - (static_cast<int32_t>(rm) << kRmShift); - Emit(encoding); } -void ArmAssembler::bx(Register rm, Condition cond) { - CHECK_NE(rm, kNoRegister); - CHECK_NE(cond, kNoCondition); - int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | - B24 | B21 | (0xfff << 8) | B4 | - (static_cast<int32_t>(rm) << kRmShift); - Emit(encoding); -} - -void ArmAssembler::MarkExceptionHandler(Label* label) { - EmitType01(AL, 1, TST, 1, PC, R0, ShifterOperand(0)); - Label l; - b(&l); - EmitBranch(AL, label, false); - Bind(&l); -} - - -void ArmAssembler::Bind(Label* label) { - CHECK(!label->IsBound()); - int bound_pc = buffer_.Size(); - while (label->IsLinked()) { - int32_t position = label->Position(); - int32_t next = buffer_.Load<int32_t>(position); - int32_t encoded = ArmAssembler::EncodeBranchOffset(bound_pc - position, next); - buffer_.Store<int32_t>(position, encoded); - label->position_ = ArmAssembler::DecodeBranchOffset(next); +uint32_t ShifterOperand::encodingThumb(int version) const { + CHECK(version == 1 || version == 2); + if (version == 1) { + LOG(FATAL) << "Invalid of use encodingThumb with version 1"; + } else { + switch (type_) { + case kImmediate: + return immed_; + case kRegister: + if (is_shift_) { + // Shifted immediate or register. + if (rs_ == kNoRegister) { + // Immediate shift. + if (shift_ == RRX) { + // RRX is encoded as an ROR with imm 0. + return ROR << 4 | static_cast<uint32_t>(rm_); + } else { + uint32_t imm3 = immed_ >> 2; + uint32_t imm2 = immed_ & 0b11; + + return imm3 << 12 | imm2 << 6 | shift_ << 4 | + static_cast<uint32_t>(rm_); + } + } else { + LOG(FATAL) << "No register-shifted register instruction available in thumb"; + return 0; + } + } else { + // Simple register + return static_cast<uint32_t>(rm_); + } + break; + default: + // Can't get here. + LOG(FATAL) << "Invalid shifter operand for thumb"; + return 0; + } } - label->BindTo(bound_pc); -} - + return 0; +} + +bool ShifterOperand::CanHoldThumb(Register rd, Register rn, Opcode opcode, + uint32_t immediate, ShifterOperand* shifter_op) { + shifter_op->type_ = kImmediate; + shifter_op->immed_ = immediate; + shifter_op->is_shift_ = false; + shifter_op->is_rotate_ = false; + switch (opcode) { + case ADD: + case SUB: + if (rn == SP) { + if (rd == SP) { + return immediate < (1 << 9); // 9 bits allowed. + } else { + return immediate < (1 << 12); // 12 bits. + } + } + if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done. + return true; + } + return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; -void ArmAssembler::EncodeUint32InTstInstructions(uint32_t data) { - // TODO: Consider using movw ip, <16 bits>. - while (!IsUint(8, data)) { - tst(R0, ShifterOperand(data & 0xFF), VS); - data >>= 8; + case MOV: + if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done. + return true; + } + return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; + case MVN: + default: + return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; } - tst(R0, ShifterOperand(data), MI); -} - - -int32_t ArmAssembler::EncodeBranchOffset(int offset, int32_t inst) { - // The offset is off by 8 due to the way the ARM CPUs read PC. - offset -= 8; - CHECK_ALIGNED(offset, 4); - CHECK(IsInt(POPCOUNT(kBranchOffsetMask), offset)) << offset; - - // Properly preserve only the bits supported in the instruction. - offset >>= 2; - offset &= kBranchOffsetMask; - return (inst & ~kBranchOffsetMask) | offset; } - -int ArmAssembler::DecodeBranchOffset(int32_t inst) { - // Sign-extend, left-shift by 2, then add 8. - return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8); -} - -void ArmAssembler::AddConstant(Register rd, int32_t value, Condition cond) { - AddConstant(rd, rd, value, cond); -} - - -void ArmAssembler::AddConstant(Register rd, Register rn, int32_t value, - Condition cond) { - if (value == 0) { - if (rd != rn) { - mov(rd, ShifterOperand(rn), cond); - } - return; - } - // We prefer to select the shorter code sequence rather than selecting add for - // positive values and sub for negatives ones, which would slightly improve - // the readability of generated code for some constants. - ShifterOperand shifter_op; - if (ShifterOperand::CanHold(value, &shifter_op)) { - add(rd, rn, shifter_op, cond); - } else if (ShifterOperand::CanHold(-value, &shifter_op)) { - sub(rd, rn, shifter_op, cond); +uint32_t Address::encodingArm() const { + CHECK(IsAbsoluteUint(12, offset_)); + uint32_t encoding; + if (offset_ < 0) { + encoding = (am_ ^ (1 << kUShift)) | -offset_; // Flip U to adjust sign. } else { - CHECK(rn != IP); - if (ShifterOperand::CanHold(~value, &shifter_op)) { - mvn(IP, shifter_op, cond); - add(rd, rn, ShifterOperand(IP), cond); - } else if (ShifterOperand::CanHold(~(-value), &shifter_op)) { - mvn(IP, shifter_op, cond); - sub(rd, rn, ShifterOperand(IP), cond); - } else { - movw(IP, Low16Bits(value), cond); - uint16_t value_high = High16Bits(value); - if (value_high != 0) { - movt(IP, value_high, cond); + encoding = am_ | offset_; + } + encoding |= static_cast<uint32_t>(rn_) << kRnShift; + return encoding; +} + + +uint32_t Address::encodingThumb(int version) const { + CHECK(version == 1 || version == 2); + uint32_t encoding = 0; + if (version == 2) { + encoding = static_cast<uint32_t>(rn_) << 16; + // Check for the T3/T4 encoding. + // PUW must Offset for T3 + // Convert ARM PU0W to PUW + // The Mode is in ARM encoding format which is: + // |P|U|0|W| + // we need this in thumb2 mode: + // |P|U|W| + + uint32_t am = am_; + int32_t offset = offset_; + if (offset < 0) { + am ^= 1 << kUShift; + offset = -offset; } - add(rd, rn, ShifterOperand(IP), cond); - } + if (offset_ < 0 || (offset >= 0 && offset < 256 && + am_ != Mode::Offset)) { + // T4 encoding. + uint32_t PUW = am >> 21; // Move down to bottom of word. + PUW = (PUW >> 1) | (PUW & 1); // Bits 3, 2 and 0. + // If P is 0 then W must be 1 (Different from ARM). + if ((PUW & 0b100) == 0) { + PUW |= 0b1; + } + encoding |= B11 | PUW << 8 | offset; + } else { + // T3 encoding (also sets op1 to 0b01). + encoding |= B23 | offset_; + } + } else { + LOG(FATAL) << "Invalid use of encodingThumb for version 1"; } + return encoding; } - -void ArmAssembler::AddConstantSetFlags(Register rd, Register rn, int32_t value, - Condition cond) { - ShifterOperand shifter_op; - if (ShifterOperand::CanHold(value, &shifter_op)) { - adds(rd, rn, shifter_op, cond); - } else if (ShifterOperand::CanHold(-value, &shifter_op)) { - subs(rd, rn, shifter_op, cond); +// This is very like the ARM encoding except the offset is 10 bits. +uint32_t Address::encodingThumbLdrdStrd() const { + uint32_t encoding; + uint32_t am = am_; + // If P is 0 then W must be 1 (Different from ARM). + uint32_t PU1W = am_ >> 21; // Move down to bottom of word. + if ((PU1W & 0b1000) == 0) { + am |= 1 << 21; // Set W bit. + } + if (offset_ < 0) { + int32_t off = -offset_; + CHECK_LT(off, 1024); + CHECK_EQ((off & 0b11), 0); // Must be multiple of 4. + encoding = (am ^ (1 << kUShift)) | off >> 2; // Flip U to adjust sign. } else { - CHECK(rn != IP); - if (ShifterOperand::CanHold(~value, &shifter_op)) { - mvn(IP, shifter_op, cond); - adds(rd, rn, ShifterOperand(IP), cond); - } else if (ShifterOperand::CanHold(~(-value), &shifter_op)) { - mvn(IP, shifter_op, cond); - subs(rd, rn, ShifterOperand(IP), cond); - } else { - movw(IP, Low16Bits(value), cond); - uint16_t value_high = High16Bits(value); - if (value_high != 0) { - movt(IP, value_high, cond); - } - adds(rd, rn, ShifterOperand(IP), cond); - } + CHECK_LT(offset_, 1024); + CHECK_EQ((offset_ & 0b11), 0); // Must be multiple of 4. + encoding = am | offset_ >> 2; } + encoding |= static_cast<uint32_t>(rn_) << 16; + return encoding; } +// Encoding for ARM addressing mode 3. +uint32_t Address::encoding3() const { + const uint32_t offset_mask = (1 << 12) - 1; + uint32_t encoding = encodingArm(); + uint32_t offset = encoding & offset_mask; + CHECK_LT(offset, 256u); + return (encoding & ~offset_mask) | ((offset & 0xf0) << 4) | (offset & 0xf); +} -void ArmAssembler::LoadImmediate(Register rd, int32_t value, Condition cond) { - ShifterOperand shifter_op; - if (ShifterOperand::CanHold(value, &shifter_op)) { - mov(rd, shifter_op, cond); - } else if (ShifterOperand::CanHold(~value, &shifter_op)) { - mvn(rd, shifter_op, cond); - } else { - movw(rd, Low16Bits(value), cond); - uint16_t value_high = High16Bits(value); - if (value_high != 0) { - movt(rd, value_high, cond); - } +// Encoding for vfp load/store addressing. +uint32_t Address::vencoding() const { + const uint32_t offset_mask = (1 << 12) - 1; + uint32_t encoding = encodingArm(); + uint32_t offset = encoding & offset_mask; + CHECK(IsAbsoluteUint(10, offset)); // In the range -1020 to +1020. + CHECK_ALIGNED(offset, 2); // Multiple of 4. + CHECK((am_ == Offset) || (am_ == NegOffset)); + uint32_t vencoding = (encoding & (0xf << kRnShift)) | (offset >> 2); + if (am_ == Offset) { + vencoding |= 1 << 23; } + return vencoding; } -bool Address::CanHoldLoadOffset(LoadOperandType type, int offset) { +bool Address::CanHoldLoadOffsetArm(LoadOperandType type, int offset) { switch (type) { case kLoadSignedByte: case kLoadSignedHalfword: @@ -1225,7 +304,7 @@ bool Address::CanHoldLoadOffset(LoadOperandType type, int offset) { } -bool Address::CanHoldStoreOffset(StoreOperandType type, int offset) { +bool Address::CanHoldStoreOffsetArm(StoreOperandType type, int offset) { switch (type) { case kStoreHalfword: case kStoreWordPair: @@ -1242,200 +321,50 @@ bool Address::CanHoldStoreOffset(StoreOperandType type, int offset) { } } - -// Implementation note: this method must emit at most one instruction when -// Address::CanHoldLoadOffset. -void ArmAssembler::LoadFromOffset(LoadOperandType type, - Register reg, - Register base, - int32_t offset, - Condition cond) { - if (!Address::CanHoldLoadOffset(type, offset)) { - CHECK(base != IP); - LoadImmediate(IP, offset, cond); - add(IP, IP, ShifterOperand(base), cond); - base = IP; - offset = 0; - } - CHECK(Address::CanHoldLoadOffset(type, offset)); +bool Address::CanHoldLoadOffsetThumb(LoadOperandType type, int offset) { switch (type) { case kLoadSignedByte: - ldrsb(reg, Address(base, offset), cond); - break; - case kLoadUnsignedByte: - ldrb(reg, Address(base, offset), cond); - break; case kLoadSignedHalfword: - ldrsh(reg, Address(base, offset), cond); - break; case kLoadUnsignedHalfword: - ldrh(reg, Address(base, offset), cond); - break; + case kLoadUnsignedByte: case kLoadWord: - ldr(reg, Address(base, offset), cond); - break; + return IsAbsoluteUint(12, offset); + case kLoadSWord: + case kLoadDWord: + return IsAbsoluteUint(10, offset); // VFP addressing mode. case kLoadWordPair: - ldrd(reg, Address(base, offset), cond); - break; - default: + return IsAbsoluteUint(10, offset); + default: LOG(FATAL) << "UNREACHABLE"; + return false; } } -// Implementation note: this method must emit at most one instruction when -// Address::CanHoldLoadOffset, as expected by JIT::GuardedLoadFromOffset. -void ArmAssembler::LoadSFromOffset(SRegister reg, - Register base, - int32_t offset, - Condition cond) { - if (!Address::CanHoldLoadOffset(kLoadSWord, offset)) { - CHECK_NE(base, IP); - LoadImmediate(IP, offset, cond); - add(IP, IP, ShifterOperand(base), cond); - base = IP; - offset = 0; - } - CHECK(Address::CanHoldLoadOffset(kLoadSWord, offset)); - vldrs(reg, Address(base, offset), cond); -} - -// Implementation note: this method must emit at most one instruction when -// Address::CanHoldLoadOffset, as expected by JIT::GuardedLoadFromOffset. -void ArmAssembler::LoadDFromOffset(DRegister reg, - Register base, - int32_t offset, - Condition cond) { - if (!Address::CanHoldLoadOffset(kLoadDWord, offset)) { - CHECK_NE(base, IP); - LoadImmediate(IP, offset, cond); - add(IP, IP, ShifterOperand(base), cond); - base = IP; - offset = 0; - } - CHECK(Address::CanHoldLoadOffset(kLoadDWord, offset)); - vldrd(reg, Address(base, offset), cond); -} -// Implementation note: this method must emit at most one instruction when -// Address::CanHoldStoreOffset. -void ArmAssembler::StoreToOffset(StoreOperandType type, - Register reg, - Register base, - int32_t offset, - Condition cond) { - if (!Address::CanHoldStoreOffset(type, offset)) { - CHECK(reg != IP); - CHECK(base != IP); - LoadImmediate(IP, offset, cond); - add(IP, IP, ShifterOperand(base), cond); - base = IP; - offset = 0; - } - CHECK(Address::CanHoldStoreOffset(type, offset)); +bool Address::CanHoldStoreOffsetThumb(StoreOperandType type, int offset) { switch (type) { - case kStoreByte: - strb(reg, Address(base, offset), cond); - break; case kStoreHalfword: - strh(reg, Address(base, offset), cond); - break; + case kStoreByte: case kStoreWord: - str(reg, Address(base, offset), cond); - break; + return IsAbsoluteUint(12, offset); + case kStoreSWord: + case kStoreDWord: + return IsAbsoluteUint(10, offset); // VFP addressing mode. case kStoreWordPair: - strd(reg, Address(base, offset), cond); - break; - default: + return IsAbsoluteUint(10, offset); + default: LOG(FATAL) << "UNREACHABLE"; + return false; } } -// Implementation note: this method must emit at most one instruction when -// Address::CanHoldStoreOffset, as expected by JIT::GuardedStoreToOffset. -void ArmAssembler::StoreSToOffset(SRegister reg, - Register base, - int32_t offset, - Condition cond) { - if (!Address::CanHoldStoreOffset(kStoreSWord, offset)) { - CHECK_NE(base, IP); - LoadImmediate(IP, offset, cond); - add(IP, IP, ShifterOperand(base), cond); - base = IP; - offset = 0; - } - CHECK(Address::CanHoldStoreOffset(kStoreSWord, offset)); - vstrs(reg, Address(base, offset), cond); -} - -// Implementation note: this method must emit at most one instruction when -// Address::CanHoldStoreOffset, as expected by JIT::GuardedStoreSToOffset. -void ArmAssembler::StoreDToOffset(DRegister reg, - Register base, - int32_t offset, - Condition cond) { - if (!Address::CanHoldStoreOffset(kStoreDWord, offset)) { - CHECK_NE(base, IP); - LoadImmediate(IP, offset, cond); - add(IP, IP, ShifterOperand(base), cond); - base = IP; - offset = 0; - } - CHECK(Address::CanHoldStoreOffset(kStoreDWord, offset)); - vstrd(reg, Address(base, offset), cond); -} - -void ArmAssembler::Push(Register rd, Condition cond) { - str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond); -} - -void ArmAssembler::Pop(Register rd, Condition cond) { - ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond); -} - -void ArmAssembler::PushList(RegList regs, Condition cond) { - stm(DB_W, SP, regs, cond); -} - -void ArmAssembler::PopList(RegList regs, Condition cond) { - ldm(IA_W, SP, regs, cond); -} - -void ArmAssembler::Mov(Register rd, Register rm, Condition cond) { - if (rd != rm) { - mov(rd, ShifterOperand(rm), cond); +void ArmAssembler::Pad(uint32_t bytes) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + for (uint32_t i = 0; i < bytes; ++i) { + buffer_.Emit<byte>(0); } } -void ArmAssembler::Lsl(Register rd, Register rm, uint32_t shift_imm, - Condition cond) { - CHECK_NE(shift_imm, 0u); // Do not use Lsl if no shift is wanted. - mov(rd, ShifterOperand(rm, LSL, shift_imm), cond); -} - -void ArmAssembler::Lsr(Register rd, Register rm, uint32_t shift_imm, - Condition cond) { - CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted. - if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. - mov(rd, ShifterOperand(rm, LSR, shift_imm), cond); -} - -void ArmAssembler::Asr(Register rd, Register rm, uint32_t shift_imm, - Condition cond) { - CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted. - if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. - mov(rd, ShifterOperand(rm, ASR, shift_imm), cond); -} - -void ArmAssembler::Ror(Register rd, Register rm, uint32_t shift_imm, - Condition cond) { - CHECK_NE(shift_imm, 0u); // Use Rrx instruction. - mov(rd, ShifterOperand(rm, ROR, shift_imm), cond); -} - -void ArmAssembler::Rrx(Register rd, Register rm, Condition cond) { - mov(rd, ShifterOperand(rm, ROR, 0), cond); -} - constexpr size_t kFramePointerSize = 4; void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, @@ -1472,7 +401,7 @@ void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void ArmAssembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); - // Compute callee saves to pop and PC + // Compute callee saves to pop and PC. RegList pop_list = 1 << PC; size_t pop_values = 1; for (size_t i = 0; i < callee_save_regs.size(); i++) { @@ -1481,12 +410,12 @@ void ArmAssembler::RemoveFrame(size_t frame_size, pop_values++; } - // Decrease frame to start of callee saves + // Decrease frame to start of callee saves. CHECK_GT(frame_size, pop_values * kFramePointerSize); size_t adjust = frame_size - (pop_values * kFramePointerSize); DecreaseFrameSize(adjust); - // Pop callee saves and PC + // Pop callee saves and PC. PopList(pop_list); } @@ -1681,7 +610,7 @@ void ArmAssembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t /*s } else { CHECK(dst.IsRegisterPair()) << dst; CHECK(src.IsRegisterPair()) << src; - // Ensure that the first move doesn't clobber the input of the second + // Ensure that the first move doesn't clobber the input of the second. if (src.AsRegisterPairHigh() != dst.AsRegisterPairLow()) { mov(dst.AsRegisterPairLow(), ShifterOperand(src.AsRegisterPairLow())); mov(dst.AsRegisterPairHigh(), ShifterOperand(src.AsRegisterPairHigh())); @@ -1743,15 +672,6 @@ void ArmAssembler::Copy(FrameOffset /*dst*/, Offset /*dest_offset*/, FrameOffset UNIMPLEMENTED(FATAL); } - -void ArmAssembler::MemoryBarrier(ManagedRegister mscratch) { - CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12); -#if ANDROID_SMP != 0 - int32_t encoding = 0xf57ff05f; // dmb - Emit(encoding); -#endif -} - void ArmAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, FrameOffset handle_scope_offset, ManagedRegister min_reg, bool null_allowed) { @@ -1770,7 +690,10 @@ void ArmAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, } cmp(in_reg.AsCoreRegister(), ShifterOperand(0)); if (!out_reg.Equals(in_reg)) { + it(EQ, kItElse); LoadImmediate(out_reg.AsCoreRegister(), 0, EQ); + } else { + it(NE); } AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE); } else { @@ -1791,6 +714,7 @@ void ArmAssembler::CreateHandleScopeEntry(FrameOffset out_off, // the address in the handle scope holding the reference. // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset) cmp(scratch.AsCoreRegister(), ShifterOperand(0)); + it(NE); AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE); } else { AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL); @@ -1806,19 +730,20 @@ void ArmAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, CHECK(in_reg.IsCoreRegister()) << in_reg; Label null_arg; if (!out_reg.Equals(in_reg)) { - LoadImmediate(out_reg.AsCoreRegister(), 0, EQ); + LoadImmediate(out_reg.AsCoreRegister(), 0, EQ); // TODO: why EQ? } cmp(in_reg.AsCoreRegister(), ShifterOperand(0)); + it(NE); LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), in_reg.AsCoreRegister(), 0, NE); } void ArmAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) { - // TODO: not validating references + // TODO: not validating references. } void ArmAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) { - // TODO: not validating references + // TODO: not validating references. } void ArmAssembler::Call(ManagedRegister mbase, Offset offset, @@ -1830,7 +755,7 @@ void ArmAssembler::Call(ManagedRegister mbase, Offset offset, LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), base.AsCoreRegister(), offset.Int32Value()); blx(scratch.AsCoreRegister()); - // TODO: place reference map on call + // TODO: place reference map on call. } void ArmAssembler::Call(FrameOffset base, Offset offset, @@ -1876,16 +801,71 @@ void ArmExceptionSlowPath::Emit(Assembler* sasm) { if (stack_adjust_ != 0) { // Fix up the frame. __ DecreaseFrameSize(stack_adjust_); } - // Pass exception object as argument - // Don't care about preserving R0 as this call won't return + // Pass exception object as argument. + // Don't care about preserving R0 as this call won't return. __ mov(R0, ShifterOperand(scratch_.AsCoreRegister())); - // Set up call to Thread::Current()->pDeliverException + // Set up call to Thread::Current()->pDeliverException. __ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value()); __ blx(R12); - // Call never returns + // Call never returns. __ bkpt(0); #undef __ } + +static int LeadingZeros(uint32_t val) { + uint32_t alt; + int32_t n; + int32_t count; + + count = 16; + n = 32; + do { + alt = val >> count; + if (alt != 0) { + n = n - count; + val = alt; + } + count >>= 1; + } while (count); + return n - val; +} + + +uint32_t ArmAssembler::ModifiedImmediate(uint32_t value) { + int32_t z_leading; + int32_t z_trailing; + uint32_t b0 = value & 0xff; + + /* Note: case of value==0 must use 0:000:0:0000000 encoding */ + if (value <= 0xFF) + return b0; // 0:000:a:bcdefgh. + if (value == ((b0 << 16) | b0)) + return (0x1 << 12) | b0; /* 0:001:a:bcdefgh */ + if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0)) + return (0x3 << 12) | b0; /* 0:011:a:bcdefgh */ + b0 = (value >> 8) & 0xff; + if (value == ((b0 << 24) | (b0 << 8))) + return (0x2 << 12) | b0; /* 0:010:a:bcdefgh */ + /* Can we do it with rotation? */ + z_leading = LeadingZeros(value); + z_trailing = 32 - LeadingZeros(~value & (value - 1)); + /* A run of eight or fewer active bits? */ + if ((z_leading + z_trailing) < 24) + return kInvalidModifiedImmediate; /* No - bail */ + /* left-justify the constant, discarding msb (known to be 1) */ + value <<= z_leading + 1; + /* Create bcdefgh */ + value >>= 25; + + /* Put it all together */ + uint32_t v = 8 + z_leading; + + uint32_t i = (v & 0b10000) >> 4; + uint32_t imm3 = (v >> 1) & 0b111; + uint32_t a = v & 1; + return value | i << 26 | imm3 << 12 | a << 7; +} + } // namespace arm } // namespace art diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 396e603..7b662e1 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -29,88 +29,118 @@ namespace art { namespace arm { -// Encodes Addressing Mode 1 - Data-processing operands defined in Section 5.1. class ShifterOperand { public: - // Data-processing operands - Uninitialized - ShifterOperand() { - type_ = -1; - encoding_ = 0; + ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister), + is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) { } - // Data-processing operands - Immediate - explicit ShifterOperand(uint32_t immediate) { - CHECK(immediate < (1 << kImmed8Bits)); - type_ = 1; - encoding_ = immediate; + explicit ShifterOperand(uint32_t immed) : type_(kImmediate), rm_(kNoRegister), rs_(kNoRegister), + is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(immed) { } - // Data-processing operands - Rotated immediate - ShifterOperand(uint32_t rotate, uint32_t immed8) { - CHECK((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits))); - type_ = 1; - encoding_ = (rotate << kRotateShift) | (immed8 << kImmed8Shift); + // Data-processing operands - Register + explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister), + is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) { } - // Data-processing operands - Register - explicit ShifterOperand(Register rm) { - type_ = 0; - encoding_ = static_cast<uint32_t>(rm); + ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister), + rs_(kNoRegister), + is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) { } - // Data-processing operands - Logical shift/rotate by immediate - ShifterOperand(Register rm, Shift shift, uint32_t shift_imm) { - CHECK(shift_imm < (1 << kShiftImmBits)); - type_ = 0; - encoding_ = shift_imm << kShiftImmShift | - static_cast<uint32_t>(shift) << kShiftShift | - static_cast<uint32_t>(rm); + ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm), + rs_(kNoRegister), + is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) { } // Data-processing operands - Logical shift/rotate by register - ShifterOperand(Register rm, Shift shift, Register rs) { - type_ = 0; - encoding_ = static_cast<uint32_t>(rs) << kShiftRegisterShift | - static_cast<uint32_t>(shift) << kShiftShift | (1 << 4) | - static_cast<uint32_t>(rm); + ShifterOperand(Register rm, Shift shift, Register rs) : type_(kRegister), rm_(rm), + rs_(rs), + is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) { + } + + bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); } + + uint32_t type() const { + CHECK(is_valid()); + return type_; } - static bool CanHold(uint32_t immediate, ShifterOperand* shifter_op) { + uint32_t encodingArm() const; + uint32_t encodingThumb(int version) const; + + bool IsEmpty() const { + return type_ == kUnknown; + } + + bool IsImmediate() const { + return type_ == kImmediate; + } + + bool IsRegister() const { + return type_ == kRegister; + } + + bool IsShift() const { + return is_shift_; + } + + uint32_t GetImmediate() const { + return immed_; + } + + Shift GetShift() const { + return shift_; + } + + Register GetRegister() const { + return rm_; + } + + enum Type { + kUnknown = -1, + kRegister, + kImmediate + }; + + static bool CanHoldArm(uint32_t immediate, ShifterOperand* shifter_op) { // Avoid the more expensive test for frequent small immediate values. if (immediate < (1 << kImmed8Bits)) { - shifter_op->type_ = 1; - shifter_op->encoding_ = (0 << kRotateShift) | (immediate << kImmed8Shift); + shifter_op->type_ = kImmediate; + shifter_op->is_rotate_ = true; + shifter_op->rotate_ = 0; + shifter_op->immed_ = immediate; return true; } // Note that immediate must be unsigned for the test to work correctly. for (int rot = 0; rot < 16; rot++) { uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot)); if (imm8 < (1 << kImmed8Bits)) { - shifter_op->type_ = 1; - shifter_op->encoding_ = (rot << kRotateShift) | (imm8 << kImmed8Shift); + shifter_op->type_ = kImmediate; + shifter_op->is_rotate_ = true; + shifter_op->rotate_ = rot; + shifter_op->immed_ = imm8; return true; } } return false; } - private: - bool is_valid() const { return (type_ == 0) || (type_ == 1); } + static bool CanHoldThumb(Register rd, Register rn, Opcode opcode, + uint32_t immediate, ShifterOperand* shifter_op); - uint32_t type() const { - CHECK(is_valid()); - return type_; - } - uint32_t encoding() const { - CHECK(is_valid()); - return encoding_; - } - - uint32_t type_; // Encodes the type field (bits 27-25) in the instruction. - uint32_t encoding_; + private: + Type type_; + Register rm_; + Register rs_; + bool is_rotate_; + bool is_shift_; + Shift shift_; + uint32_t rotate_; + uint32_t immed_; - friend class ArmAssembler; #ifdef SOURCE_ASSEMBLER_SUPPORT friend class BinaryAssembler; #endif @@ -152,10 +182,10 @@ enum BlockAddressMode { IB_W = (8|4|1) << 21 // increment before with writeback to base }; - class Address { public: - // Memory operand addressing mode + // Memory operand addressing mode (in ARM encoding form. For others we need + // to adjust) enum Mode { // bit encoding P U W Offset = (8|4|0) << 21, // offset (w/o writeback to base) @@ -166,273 +196,366 @@ class Address { NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback }; - explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) { - CHECK(IsAbsoluteUint(12, offset)); - if (offset < 0) { - encoding_ = (am ^ (1 << kUShift)) | -offset; // Flip U to adjust sign. - } else { - encoding_ = am | offset; - } - encoding_ |= static_cast<uint32_t>(rn) << kRnShift; + explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), offset_(offset), + am_(am) { } - static bool CanHoldLoadOffset(LoadOperandType type, int offset); - static bool CanHoldStoreOffset(StoreOperandType type, int offset); + static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset); + static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset); - private: - uint32_t encoding() const { return encoding_; } - - // Encoding for addressing mode 3. - uint32_t encoding3() const { - const uint32_t offset_mask = (1 << 12) - 1; - uint32_t offset = encoding_ & offset_mask; - CHECK_LT(offset, 256u); - return (encoding_ & ~offset_mask) | ((offset & 0xf0) << 4) | (offset & 0xf); + static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset); + static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset); + + uint32_t encodingArm() const; + uint32_t encodingThumb(int version) const; + + uint32_t encoding3() const; + uint32_t vencoding() const; + + uint32_t encodingThumbLdrdStrd() const; + + Register GetRegister() const { + return rn_; } - // Encoding for vfp load/store addressing. - uint32_t vencoding() const { - const uint32_t offset_mask = (1 << 12) - 1; - uint32_t offset = encoding_ & offset_mask; - CHECK(IsAbsoluteUint(10, offset)); // In the range -1020 to +1020. - CHECK_ALIGNED(offset, 2); // Multiple of 4. - int mode = encoding_ & ((8|4|1) << 21); - CHECK((mode == Offset) || (mode == NegOffset)); - uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2); - if (mode == Offset) { - vencoding |= 1 << 23; - } - return vencoding; + int32_t GetOffset() const { + return offset_; } - uint32_t encoding_; + Mode GetMode() const { + return am_; + } + + private: + Register rn_; + int32_t offset_; + Mode am_; +}; + +// Instruction encoding bits. +enum { + H = 1 << 5, // halfword (or byte) + L = 1 << 20, // load (or store) + S = 1 << 20, // set condition code (or leave unchanged) + W = 1 << 21, // writeback base register (or leave unchanged) + A = 1 << 21, // accumulate in multiply instruction (or not) + B = 1 << 22, // unsigned byte (or word) + N = 1 << 22, // long (or short) + U = 1 << 23, // positive (or negative) offset/index + P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing) + I = 1 << 25, // immediate shifter operand (or not) + + B0 = 1, + B1 = 1 << 1, + B2 = 1 << 2, + B3 = 1 << 3, + B4 = 1 << 4, + B5 = 1 << 5, + B6 = 1 << 6, + B7 = 1 << 7, + B8 = 1 << 8, + B9 = 1 << 9, + B10 = 1 << 10, + B11 = 1 << 11, + B12 = 1 << 12, + B13 = 1 << 13, + B14 = 1 << 14, + B15 = 1 << 15, + B16 = 1 << 16, + B17 = 1 << 17, + B18 = 1 << 18, + B19 = 1 << 19, + B20 = 1 << 20, + B21 = 1 << 21, + B22 = 1 << 22, + B23 = 1 << 23, + B24 = 1 << 24, + B25 = 1 << 25, + B26 = 1 << 26, + B27 = 1 << 27, + B28 = 1 << 28, + B29 = 1 << 29, + B30 = 1 << 30, + B31 = 1 << 31, + + // Instruction bit masks. + RdMask = 15 << 12, // in str instruction + CondMask = 15 << 28, + CoprocessorMask = 15 << 8, + OpCodeMask = 15 << 21, // in data-processing instructions + Imm24Mask = (1 << 24) - 1, + Off12Mask = (1 << 12) - 1, + + // ldrex/strex register field encodings. + kLdExRnShift = 16, + kLdExRtShift = 12, + kStrExRnShift = 16, + kStrExRdShift = 12, + kStrExRtShift = 0, +}; - friend class ArmAssembler; +// IfThen state for IT instructions. +enum ItState { + kItOmitted, + kItThen, + kItT = kItThen, + kItElse, + kItE = kItElse }; +constexpr uint32_t kNoItCondition = 3; +constexpr uint32_t kInvalidModifiedImmediate = -1; -class ArmAssembler FINAL : public Assembler { +extern const char* kRegisterNames[]; +extern const char* kConditionNames[]; +extern std::ostream& operator<<(std::ostream& os, const Register& rhs); +extern std::ostream& operator<<(std::ostream& os, const SRegister& rhs); +extern std::ostream& operator<<(std::ostream& os, const DRegister& rhs); +extern std::ostream& operator<<(std::ostream& os, const Condition& rhs); + +// This is an abstract ARM assembler. Subclasses provide assemblers for the individual +// instruction sets (ARM32, Thumb2, etc.) +// +class ArmAssembler : public Assembler { public: - ArmAssembler() {} virtual ~ArmAssembler() {} + // Is this assembler for the thumb instruction set? + virtual bool IsThumb() const = 0; + // Data-processing instructions. - void and_(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void eor(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void sub(Register rd, Register rn, ShifterOperand so, Condition cond = AL); - void subs(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void rsb(Register rd, Register rn, ShifterOperand so, Condition cond = AL); - void rsbs(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void add(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void adds(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void adc(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void sbc(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void rsc(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void tst(Register rn, ShifterOperand so, Condition cond = AL); + virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void teq(Register rn, ShifterOperand so, Condition cond = AL); + virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void cmp(Register rn, ShifterOperand so, Condition cond = AL); + virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void cmn(Register rn, ShifterOperand so, Condition cond = AL); + virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void orr(Register rd, Register rn, ShifterOperand so, Condition cond = AL); - void orrs(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void mov(Register rd, ShifterOperand so, Condition cond = AL); - void movs(Register rd, ShifterOperand so, Condition cond = AL); + virtual void mov(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; - void bic(Register rd, Register rn, ShifterOperand so, Condition cond = AL); + virtual void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - void mvn(Register rd, ShifterOperand so, Condition cond = AL); - void mvns(Register rd, ShifterOperand so, Condition cond = AL); + virtual void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; // Miscellaneous data-processing instructions. - void clz(Register rd, Register rm, Condition cond = AL); - void movw(Register rd, uint16_t imm16, Condition cond = AL); - void movt(Register rd, uint16_t imm16, Condition cond = AL); + virtual void clz(Register rd, Register rm, Condition cond = AL) = 0; + virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0; + virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0; // Multiply instructions. - void mul(Register rd, Register rn, Register rm, Condition cond = AL); - void mla(Register rd, Register rn, Register rm, Register ra, - Condition cond = AL); - void mls(Register rd, Register rn, Register rm, Register ra, - Condition cond = AL); - void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, - Condition cond = AL); + virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0; + virtual void mla(Register rd, Register rn, Register rm, Register ra, + Condition cond = AL) = 0; + virtual void mls(Register rd, Register rn, Register rm, Register ra, + Condition cond = AL) = 0; + virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, + Condition cond = AL) = 0; + + virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0; + virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0; // Load/store instructions. - void ldr(Register rd, Address ad, Condition cond = AL); - void str(Register rd, Address ad, Condition cond = AL); + virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0; + virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0; - void ldrb(Register rd, Address ad, Condition cond = AL); - void strb(Register rd, Address ad, Condition cond = AL); + virtual void ldrb(Register rd, const Address& ad, Condition cond = AL) = 0; + virtual void strb(Register rd, const Address& ad, Condition cond = AL) = 0; - void ldrh(Register rd, Address ad, Condition cond = AL); - void strh(Register rd, Address ad, Condition cond = AL); + virtual void ldrh(Register rd, const Address& ad, Condition cond = AL) = 0; + virtual void strh(Register rd, const Address& ad, Condition cond = AL) = 0; - void ldrsb(Register rd, Address ad, Condition cond = AL); - void ldrsh(Register rd, Address ad, Condition cond = AL); + virtual void ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0; + virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0; - void ldrd(Register rd, Address ad, Condition cond = AL); - void strd(Register rd, Address ad, Condition cond = AL); + virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0; + virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0; - void ldm(BlockAddressMode am, Register base, - RegList regs, Condition cond = AL); - void stm(BlockAddressMode am, Register base, - RegList regs, Condition cond = AL); + virtual void ldm(BlockAddressMode am, Register base, + RegList regs, Condition cond = AL) = 0; + virtual void stm(BlockAddressMode am, Register base, + RegList regs, Condition cond = AL) = 0; - void ldrex(Register rd, Register rn, Condition cond = AL); - void strex(Register rd, Register rt, Register rn, Condition cond = AL); + virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0; + virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0; // Miscellaneous instructions. - void clrex(); - void nop(Condition cond = AL); + virtual void clrex(Condition cond = AL) = 0; + virtual void nop(Condition cond = AL) = 0; // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. - void bkpt(uint16_t imm16); - void svc(uint32_t imm24); + virtual void bkpt(uint16_t imm16) = 0; + virtual void svc(uint32_t imm24) = 0; + + virtual void it(Condition firstcond, ItState i1 = kItOmitted, + ItState i2 = kItOmitted, ItState i3 = kItOmitted) { + // Ignored if not supported. + } + + virtual void cbz(Register rn, Label* target) = 0; + virtual void cbnz(Register rn, Label* target) = 0; // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles). - void vmovsr(SRegister sn, Register rt, Condition cond = AL); - void vmovrs(Register rt, SRegister sn, Condition cond = AL); - void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL); - void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL); - void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL); - void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL); - void vmovs(SRegister sd, SRegister sm, Condition cond = AL); - void vmovd(DRegister dd, DRegister dm, Condition cond = AL); + virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0; + virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0; + virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0; + virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0; + virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0; + virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0; + virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0; // Returns false if the immediate cannot be encoded. - bool vmovs(SRegister sd, float s_imm, Condition cond = AL); - bool vmovd(DRegister dd, double d_imm, Condition cond = AL); - - void vldrs(SRegister sd, Address ad, Condition cond = AL); - void vstrs(SRegister sd, Address ad, Condition cond = AL); - void vldrd(DRegister dd, Address ad, Condition cond = AL); - void vstrd(DRegister dd, Address ad, Condition cond = AL); - - void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); - void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); - void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); - void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); - void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); - void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); - void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); - void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); - void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); - void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); - void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); - void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); - - void vabss(SRegister sd, SRegister sm, Condition cond = AL); - void vabsd(DRegister dd, DRegister dm, Condition cond = AL); - void vnegs(SRegister sd, SRegister sm, Condition cond = AL); - void vnegd(DRegister dd, DRegister dm, Condition cond = AL); - void vsqrts(SRegister sd, SRegister sm, Condition cond = AL); - void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL); - - void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL); - void vcvtds(DRegister dd, SRegister sm, Condition cond = AL); - void vcvtis(SRegister sd, SRegister sm, Condition cond = AL); - void vcvtid(SRegister sd, DRegister dm, Condition cond = AL); - void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL); - void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL); - void vcvtus(SRegister sd, SRegister sm, Condition cond = AL); - void vcvtud(SRegister sd, DRegister dm, Condition cond = AL); - void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL); - void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL); - - void vcmps(SRegister sd, SRegister sm, Condition cond = AL); - void vcmpd(DRegister dd, DRegister dm, Condition cond = AL); - void vcmpsz(SRegister sd, Condition cond = AL); - void vcmpdz(DRegister dd, Condition cond = AL); - void vmstat(Condition cond = AL); // VMRS APSR_nzcv, FPSCR + virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0; + virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0; + + virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0; + virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0; + virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0; + virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0; + + virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; + virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; + virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; + virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; + virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; + virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; + virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; + virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; + virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; + virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; + virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; + virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; + + virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0; + virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0; + virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0; + + virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0; + virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0; + virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0; + virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0; + virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0; + virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0; + + virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0; + virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0; + virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0; + virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0; + virtual void vmstat(Condition cond = AL) = 0; // VMRS APSR_nzcv, FPSCR + + virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0; + virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0; + virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0; + virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0; // Branch instructions. - void b(Label* label, Condition cond = AL); - void bl(Label* label, Condition cond = AL); - void blx(Register rm, Condition cond = AL); - void bx(Register rm, Condition cond = AL); + virtual void b(Label* label, Condition cond = AL) = 0; + virtual void bl(Label* label, Condition cond = AL) = 0; + virtual void blx(Register rm, Condition cond = AL) = 0; + virtual void bx(Register rm, Condition cond = AL) = 0; + + void Pad(uint32_t bytes); // Macros. + // Most of these are pure virtual as they need to be implemented per instruction set. + // Add signed constant value to rd. May clobber IP. - void AddConstant(Register rd, int32_t value, Condition cond = AL); - void AddConstant(Register rd, Register rn, int32_t value, - Condition cond = AL); - void AddConstantSetFlags(Register rd, Register rn, int32_t value, - Condition cond = AL); - void AddConstantWithCarry(Register rd, Register rn, int32_t value, - Condition cond = AL); + virtual void AddConstant(Register rd, int32_t value, Condition cond = AL) = 0; + virtual void AddConstant(Register rd, Register rn, int32_t value, + Condition cond = AL) = 0; + virtual void AddConstantSetFlags(Register rd, Register rn, int32_t value, + Condition cond = AL) = 0; + virtual void AddConstantWithCarry(Register rd, Register rn, int32_t value, + Condition cond = AL) = 0; // Load and Store. May clobber IP. - void LoadImmediate(Register rd, int32_t value, Condition cond = AL); - void LoadSImmediate(SRegister sd, float value, Condition cond = AL); - void LoadDImmediate(DRegister dd, double value, - Register scratch, Condition cond = AL); - void MarkExceptionHandler(Label* label); - void LoadFromOffset(LoadOperandType type, - Register reg, - Register base, - int32_t offset, - Condition cond = AL); - void StoreToOffset(StoreOperandType type, - Register reg, - Register base, - int32_t offset, - Condition cond = AL); - void LoadSFromOffset(SRegister reg, - Register base, - int32_t offset, - Condition cond = AL); - void StoreSToOffset(SRegister reg, - Register base, - int32_t offset, - Condition cond = AL); - void LoadDFromOffset(DRegister reg, - Register base, - int32_t offset, - Condition cond = AL); - void StoreDToOffset(DRegister reg, - Register base, - int32_t offset, - Condition cond = AL); - - void Push(Register rd, Condition cond = AL); - void Pop(Register rd, Condition cond = AL); - - void PushList(RegList regs, Condition cond = AL); - void PopList(RegList regs, Condition cond = AL); - - void Mov(Register rd, Register rm, Condition cond = AL); + virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0; + virtual void LoadSImmediate(SRegister sd, float value, Condition cond = AL) = 0; + virtual void LoadDImmediate(DRegister dd, double value, + Register scratch, Condition cond = AL) = 0; + virtual void MarkExceptionHandler(Label* label) = 0; + virtual void LoadFromOffset(LoadOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond = AL) = 0; + virtual void StoreToOffset(StoreOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond = AL) = 0; + virtual void LoadSFromOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond = AL) = 0; + virtual void StoreSToOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond = AL) = 0; + virtual void LoadDFromOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond = AL) = 0; + virtual void StoreDToOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond = AL) = 0; + + virtual void Push(Register rd, Condition cond = AL) = 0; + virtual void Pop(Register rd, Condition cond = AL) = 0; + + virtual void PushList(RegList regs, Condition cond = AL) = 0; + virtual void PopList(RegList regs, Condition cond = AL) = 0; + + virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0; // Convenience shift instructions. Use mov instruction with shifter operand // for variants setting the status flags or using a register shift count. - void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); - void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); - void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); - void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); - void Rrx(Register rd, Register rm, Condition cond = AL); - - // Encode a signed constant in tst instructions, only affecting the flags. - void EncodeUint32InTstInstructions(uint32_t data); - // ... and decode from a pc pointing to the start of encoding instructions. - static uint32_t DecodeUint32FromTstInstructions(uword pc); + virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0; + virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0; + virtual void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0; + virtual void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0; + virtual void Rrx(Register rd, Register rm, Condition cond = AL) = 0; + static bool IsInstructionForExceptionHandling(uword pc); - // Emit data (e.g. encoded instruction or immediate) to the - // instruction stream. - void Emit(int32_t value); - void Bind(Label* label); + virtual void Bind(Label* label) = 0; + + virtual void CompareAndBranchIfZero(Register r, Label* label) = 0; + virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0; // // Overridden common assembler high-level functionality @@ -445,7 +568,7 @@ class ArmAssembler FINAL : public Assembler { // Emit code that will remove an activation from the stack void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) - OVERRIDE; + OVERRIDE; void IncreaseFrameSize(size_t adjust) OVERRIDE; void DecreaseFrameSize(size_t adjust) OVERRIDE; @@ -509,8 +632,6 @@ class ArmAssembler FINAL : public Assembler { void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, ManagedRegister scratch, size_t size) OVERRIDE; - void MemoryBarrier(ManagedRegister scratch) OVERRIDE; - // Sign extension void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE; @@ -550,81 +671,9 @@ class ArmAssembler FINAL : public Assembler { // and branch to a ExceptionSlowPath if it is. void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE; - private: - void EmitType01(Condition cond, - int type, - Opcode opcode, - int set_cc, - Register rn, - Register rd, - ShifterOperand so); - - void EmitType5(Condition cond, int offset, bool link); - - void EmitMemOp(Condition cond, - bool load, - bool byte, - Register rd, - Address ad); - - void EmitMemOpAddressMode3(Condition cond, - int32_t mode, - Register rd, - Address ad); - - void EmitMultiMemOp(Condition cond, - BlockAddressMode am, - bool load, - Register base, - RegList regs); - - void EmitShiftImmediate(Condition cond, - Shift opcode, - Register rd, - Register rm, - ShifterOperand so); - - void EmitShiftRegister(Condition cond, - Shift opcode, - Register rd, - Register rm, - ShifterOperand so); - - void EmitMulOp(Condition cond, - int32_t opcode, - Register rd, - Register rn, - Register rm, - Register rs); - - void EmitVFPsss(Condition cond, - int32_t opcode, - SRegister sd, - SRegister sn, - SRegister sm); - - void EmitVFPddd(Condition cond, - int32_t opcode, - DRegister dd, - DRegister dn, - DRegister dm); - - void EmitVFPsd(Condition cond, - int32_t opcode, - SRegister sd, - DRegister dm); - - void EmitVFPds(Condition cond, - int32_t opcode, - DRegister dd, - SRegister sm); - - void EmitBranch(Condition cond, Label* label, bool link); - static int32_t EncodeBranchOffset(int offset, int32_t inst); - static int DecodeBranchOffset(int32_t inst); - int32_t EncodeTstOffset(int offset, int32_t inst); - int DecodeTstOffset(int32_t inst); + static uint32_t ModifiedImmediate(uint32_t value); + protected: // Returns whether or not the given register is used for passing parameters. static int RegisterCompare(const Register* reg1, const Register* reg2) { return *reg1 - *reg2; diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc new file mode 100644 index 0000000..b2bb20f --- /dev/null +++ b/compiler/utils/arm/assembler_arm32.cc @@ -0,0 +1,1423 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assembler_arm32.h" + +#include "base/logging.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "offsets.h" +#include "thread.h" +#include "utils.h" + +namespace art { +namespace arm { + +void Arm32Assembler::and_(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), AND, 0, rn, rd, so); +} + + +void Arm32Assembler::eor(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), EOR, 0, rn, rd, so); +} + + +void Arm32Assembler::sub(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), SUB, 0, rn, rd, so); +} + +void Arm32Assembler::rsb(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), RSB, 0, rn, rd, so); +} + +void Arm32Assembler::rsbs(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), RSB, 1, rn, rd, so); +} + + +void Arm32Assembler::add(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), ADD, 0, rn, rd, so); +} + + +void Arm32Assembler::adds(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), ADD, 1, rn, rd, so); +} + + +void Arm32Assembler::subs(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), SUB, 1, rn, rd, so); +} + + +void Arm32Assembler::adc(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), ADC, 0, rn, rd, so); +} + + +void Arm32Assembler::sbc(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), SBC, 0, rn, rd, so); +} + + +void Arm32Assembler::rsc(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), RSC, 0, rn, rd, so); +} + + +void Arm32Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) { + CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker. + EmitType01(cond, so.type(), TST, 1, rn, R0, so); +} + + +void Arm32Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) { + CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker. + EmitType01(cond, so.type(), TEQ, 1, rn, R0, so); +} + + +void Arm32Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), CMP, 1, rn, R0, so); +} + + +void Arm32Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), CMN, 1, rn, R0, so); +} + + +void Arm32Assembler::orr(Register rd, Register rn, + const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), ORR, 0, rn, rd, so); +} + + +void Arm32Assembler::orrs(Register rd, Register rn, + const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), ORR, 1, rn, rd, so); +} + + +void Arm32Assembler::mov(Register rd, const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), MOV, 0, R0, rd, so); +} + + +void Arm32Assembler::movs(Register rd, const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), MOV, 1, R0, rd, so); +} + + +void Arm32Assembler::bic(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitType01(cond, so.type(), BIC, 0, rn, rd, so); +} + + +void Arm32Assembler::mvn(Register rd, const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), MVN, 0, R0, rd, so); +} + + +void Arm32Assembler::mvns(Register rd, const ShifterOperand& so, Condition cond) { + EmitType01(cond, so.type(), MVN, 1, R0, rd, so); +} + + +void Arm32Assembler::mul(Register rd, Register rn, Register rm, Condition cond) { + // Assembler registers rd, rn, rm are encoded as rn, rm, rs. + EmitMulOp(cond, 0, R0, rd, rn, rm); +} + + +void Arm32Assembler::mla(Register rd, Register rn, Register rm, Register ra, + Condition cond) { + // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. + EmitMulOp(cond, B21, ra, rd, rn, rm); +} + + +void Arm32Assembler::mls(Register rd, Register rn, Register rm, Register ra, + Condition cond) { + // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. + EmitMulOp(cond, B22 | B21, ra, rd, rn, rm); +} + + +void Arm32Assembler::umull(Register rd_lo, Register rd_hi, Register rn, + Register rm, Condition cond) { + // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. + EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm); +} + + +void Arm32Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rn, kNoRegister); + CHECK_NE(rm, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = B26 | B25 | B24 | B20 | + B15 | B14 | B13 | B12 | + (static_cast<int32_t>(cond) << kConditionShift) | + (static_cast<int32_t>(rn) << 0) | + (static_cast<int32_t>(rd) << 16) | + (static_cast<int32_t>(rm) << 8) | + B4; + Emit(encoding); +} + + +void Arm32Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rn, kNoRegister); + CHECK_NE(rm, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = B26 | B25 | B24 | B21 | B20 | + B15 | B14 | B13 | B12 | + (static_cast<int32_t>(cond) << kConditionShift) | + (static_cast<int32_t>(rn) << 0) | + (static_cast<int32_t>(rd) << 16) | + (static_cast<int32_t>(rm) << 8) | + B4; + Emit(encoding); +} + + +void Arm32Assembler::ldr(Register rd, const Address& ad, Condition cond) { + EmitMemOp(cond, true, false, rd, ad); +} + + +void Arm32Assembler::str(Register rd, const Address& ad, Condition cond) { + EmitMemOp(cond, false, false, rd, ad); +} + + +void Arm32Assembler::ldrb(Register rd, const Address& ad, Condition cond) { + EmitMemOp(cond, true, true, rd, ad); +} + + +void Arm32Assembler::strb(Register rd, const Address& ad, Condition cond) { + EmitMemOp(cond, false, true, rd, ad); +} + + +void Arm32Assembler::ldrh(Register rd, const Address& ad, Condition cond) { + EmitMemOpAddressMode3(cond, L | B7 | H | B4, rd, ad); +} + + +void Arm32Assembler::strh(Register rd, const Address& ad, Condition cond) { + EmitMemOpAddressMode3(cond, B7 | H | B4, rd, ad); +} + + +void Arm32Assembler::ldrsb(Register rd, const Address& ad, Condition cond) { + EmitMemOpAddressMode3(cond, L | B7 | B6 | B4, rd, ad); +} + + +void Arm32Assembler::ldrsh(Register rd, const Address& ad, Condition cond) { + EmitMemOpAddressMode3(cond, L | B7 | B6 | H | B4, rd, ad); +} + + +void Arm32Assembler::ldrd(Register rd, const Address& ad, Condition cond) { + CHECK_EQ(rd % 2, 0); + EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, ad); +} + + +void Arm32Assembler::strd(Register rd, const Address& ad, Condition cond) { + CHECK_EQ(rd % 2, 0); + EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, ad); +} + + +void Arm32Assembler::ldm(BlockAddressMode am, + Register base, + RegList regs, + Condition cond) { + EmitMultiMemOp(cond, am, true, base, regs); +} + + +void Arm32Assembler::stm(BlockAddressMode am, + Register base, + RegList regs, + Condition cond) { + EmitMultiMemOp(cond, am, false, base, regs); +} + + +void Arm32Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm); +} + + +bool Arm32Assembler::vmovs(SRegister sd, float s_imm, Condition cond) { + uint32_t imm32 = bit_cast<uint32_t, float>(s_imm); + if (((imm32 & ((1 << 19) - 1)) == 0) && + ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) || + (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) { + uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) | + ((imm32 >> 19) & ((1 << 6) -1)); + EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf), + sd, S0, S0); + return true; + } + return false; +} + + +bool Arm32Assembler::vmovd(DRegister dd, double d_imm, Condition cond) { + uint64_t imm64 = bit_cast<uint64_t, double>(d_imm); + if (((imm64 & ((1LL << 48) - 1)) == 0) && + ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) || + (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) { + uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) | + ((imm64 >> 48) & ((1 << 6) -1)); + EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf), + dd, D0, D0); + return true; + } + return false; +} + + +void Arm32Assembler::vadds(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B21 | B20, sd, sn, sm); +} + + +void Arm32Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B21 | B20, dd, dn, dm); +} + + +void Arm32Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm); +} + + +void Arm32Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm); +} + + +void Arm32Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B21, sd, sn, sm); +} + + +void Arm32Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B21, dd, dn, dm); +} + + +void Arm32Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, 0, sd, sn, sm); +} + + +void Arm32Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, 0, dd, dn, dm); +} + + +void Arm32Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B6, sd, sn, sm); +} + + +void Arm32Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B6, dd, dn, dm); +} + + +void Arm32Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B23, sd, sn, sm); +} + + +void Arm32Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B23, dd, dn, dm); +} + + +void Arm32Assembler::vabss(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm); +} + + +void Arm32Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm); +} + + +void Arm32Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm); +} + +void Arm32Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm); +} + + +void Arm32Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) { + EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm); +} + + +void Arm32Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) { + EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm); +} + + +void Arm32Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) { + EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm); +} + + +void Arm32Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) { + EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm); +} + + +void Arm32Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) { + EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm); +} + + +void Arm32Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) { + EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm); +} + + +void Arm32Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm); +} + + +void Arm32Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm); +} + + +void Arm32Assembler::vcmpsz(SRegister sd, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0); +} + + +void Arm32Assembler::vcmpdz(DRegister dd, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0); +} + +void Arm32Assembler::b(Label* label, Condition cond) { + EmitBranch(cond, label, false); +} + + +void Arm32Assembler::bl(Label* label, Condition cond) { + EmitBranch(cond, label, true); +} + + +void Arm32Assembler::MarkExceptionHandler(Label* label) { + EmitType01(AL, 1, TST, 1, PC, R0, ShifterOperand(0)); + Label l; + b(&l); + EmitBranch(AL, label, false); + Bind(&l); +} + + +void Arm32Assembler::Emit(int32_t value) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + buffer_.Emit<int32_t>(value); +} + + +void Arm32Assembler::EmitType01(Condition cond, + int type, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | + type << kTypeShift | + static_cast<int32_t>(opcode) << kOpcodeShift | + set_cc << kSShift | + static_cast<int32_t>(rn) << kRnShift | + static_cast<int32_t>(rd) << kRdShift | + so.encodingArm(); + Emit(encoding); +} + + +void Arm32Assembler::EmitType5(Condition cond, int offset, bool link) { + CHECK_NE(cond, kNoCondition); + int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | + 5 << kTypeShift | + (link ? 1 : 0) << kLinkShift; + Emit(Arm32Assembler::EncodeBranchOffset(offset, encoding)); +} + + +void Arm32Assembler::EmitMemOp(Condition cond, + bool load, + bool byte, + Register rd, + const Address& ad) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(cond, kNoCondition); + const Address& addr = static_cast<const Address&>(ad); + + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B26 | + (load ? L : 0) | + (byte ? B : 0) | + (static_cast<int32_t>(rd) << kRdShift) | + addr.encodingArm(); + Emit(encoding); +} + + +void Arm32Assembler::EmitMemOpAddressMode3(Condition cond, + int32_t mode, + Register rd, + const Address& ad) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(cond, kNoCondition); + const Address& addr = static_cast<const Address&>(ad); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B22 | + mode | + (static_cast<int32_t>(rd) << kRdShift) | + addr.encoding3(); + Emit(encoding); +} + + +void Arm32Assembler::EmitMultiMemOp(Condition cond, + BlockAddressMode am, + bool load, + Register base, + RegList regs) { + CHECK_NE(base, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | + am | + (load ? L : 0) | + (static_cast<int32_t>(base) << kRnShift) | + regs; + Emit(encoding); +} + + +void Arm32Assembler::EmitShiftImmediate(Condition cond, + Shift opcode, + Register rd, + Register rm, + const ShifterOperand& so) { + CHECK_NE(cond, kNoCondition); + CHECK(so.IsImmediate()); + int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | + static_cast<int32_t>(MOV) << kOpcodeShift | + static_cast<int32_t>(rd) << kRdShift | + so.encodingArm() << kShiftImmShift | + static_cast<int32_t>(opcode) << kShiftShift | + static_cast<int32_t>(rm); + Emit(encoding); +} + + +void Arm32Assembler::EmitShiftRegister(Condition cond, + Shift opcode, + Register rd, + Register rm, + const ShifterOperand& so) { + CHECK_NE(cond, kNoCondition); + CHECK(so.IsRegister()); + int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | + static_cast<int32_t>(MOV) << kOpcodeShift | + static_cast<int32_t>(rd) << kRdShift | + so.encodingArm() << kShiftRegisterShift | + static_cast<int32_t>(opcode) << kShiftShift | + B4 | + static_cast<int32_t>(rm); + Emit(encoding); +} + + +void Arm32Assembler::EmitBranch(Condition cond, Label* label, bool link) { + if (label->IsBound()) { + EmitType5(cond, label->Position() - buffer_.Size(), link); + } else { + int position = buffer_.Size(); + // Use the offset field of the branch instruction for linking the sites. + EmitType5(cond, label->position_, link); + label->LinkTo(position); + } +} + + +void Arm32Assembler::clz(Register rd, Register rm, Condition cond) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rm, kNoRegister); + CHECK_NE(cond, kNoCondition); + CHECK_NE(rd, PC); + CHECK_NE(rm, PC); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B24 | B22 | B21 | (0xf << 16) | + (static_cast<int32_t>(rd) << kRdShift) | + (0xf << 8) | B4 | static_cast<int32_t>(rm); + Emit(encoding); +} + + +void Arm32Assembler::movw(Register rd, uint16_t imm16, Condition cond) { + CHECK_NE(cond, kNoCondition); + int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | + B25 | B24 | ((imm16 >> 12) << 16) | + static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff); + Emit(encoding); +} + + +void Arm32Assembler::movt(Register rd, uint16_t imm16, Condition cond) { + CHECK_NE(cond, kNoCondition); + int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | + B25 | B24 | B22 | ((imm16 >> 12) << 16) | + static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff); + Emit(encoding); +} + + +void Arm32Assembler::EmitMulOp(Condition cond, int32_t opcode, + Register rd, Register rn, + Register rm, Register rs) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rn, kNoRegister); + CHECK_NE(rm, kNoRegister); + CHECK_NE(rs, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = opcode | + (static_cast<int32_t>(cond) << kConditionShift) | + (static_cast<int32_t>(rn) << kRnShift) | + (static_cast<int32_t>(rd) << kRdShift) | + (static_cast<int32_t>(rs) << kRsShift) | + B7 | B4 | + (static_cast<int32_t>(rm) << kRmShift); + Emit(encoding); +} + +void Arm32Assembler::ldrex(Register rt, Register rn, Condition cond) { + CHECK_NE(rn, kNoRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B24 | + B23 | + L | + (static_cast<int32_t>(rn) << kLdExRnShift) | + (static_cast<int32_t>(rt) << kLdExRtShift) | + B11 | B10 | B9 | B8 | B7 | B4 | B3 | B2 | B1 | B0; + Emit(encoding); +} + + +void Arm32Assembler::strex(Register rd, + Register rt, + Register rn, + Condition cond) { + CHECK_NE(rn, kNoRegister); + CHECK_NE(rd, kNoRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B24 | + B23 | + (static_cast<int32_t>(rn) << kStrExRnShift) | + (static_cast<int32_t>(rd) << kStrExRdShift) | + B11 | B10 | B9 | B8 | B7 | B4 | + (static_cast<int32_t>(rt) << kStrExRtShift); + Emit(encoding); +} + + +void Arm32Assembler::clrex(Condition cond) { + CHECK_EQ(cond, AL); // This cannot be conditional on ARM. + int32_t encoding = (kSpecialCondition << kConditionShift) | + B26 | B24 | B22 | B21 | B20 | (0xff << 12) | B4 | 0xf; + Emit(encoding); +} + + +void Arm32Assembler::nop(Condition cond) { + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B25 | B24 | B21 | (0xf << 12); + Emit(encoding); +} + + +void Arm32Assembler::vmovsr(SRegister sn, Register rt, Condition cond) { + CHECK_NE(sn, kNoSRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | + ((static_cast<int32_t>(sn) >> 1)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sn) & 1)*B7) | B4; + Emit(encoding); +} + + +void Arm32Assembler::vmovrs(Register rt, SRegister sn, Condition cond) { + CHECK_NE(sn, kNoSRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B20 | + ((static_cast<int32_t>(sn) >> 1)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sn) & 1)*B7) | B4; + Emit(encoding); +} + + +void Arm32Assembler::vmovsrr(SRegister sm, Register rt, Register rt2, + Condition cond) { + CHECK_NE(sm, kNoSRegister); + CHECK_NE(sm, S31); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sm) & 1)*B5) | B4 | + (static_cast<int32_t>(sm) >> 1); + Emit(encoding); +} + + +void Arm32Assembler::vmovrrs(Register rt, Register rt2, SRegister sm, + Condition cond) { + CHECK_NE(sm, kNoSRegister); + CHECK_NE(sm, S31); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CHECK_NE(rt, rt2); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | B20 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sm) & 1)*B5) | B4 | + (static_cast<int32_t>(sm) >> 1); + Emit(encoding); +} + + +void Arm32Assembler::vmovdrr(DRegister dm, Register rt, Register rt2, + Condition cond) { + CHECK_NE(dm, kNoDRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 | + ((static_cast<int32_t>(dm) >> 4)*B5) | B4 | + (static_cast<int32_t>(dm) & 0xf); + Emit(encoding); +} + + +void Arm32Assembler::vmovrrd(Register rt, Register rt2, DRegister dm, + Condition cond) { + CHECK_NE(dm, kNoDRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CHECK_NE(rt, rt2); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | B20 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 | + ((static_cast<int32_t>(dm) >> 4)*B5) | B4 | + (static_cast<int32_t>(dm) & 0xf); + Emit(encoding); +} + + +void Arm32Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(sd, kNoSRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | B20 | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + B11 | B9 | addr.vencoding(); + Emit(encoding); +} + + +void Arm32Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC); + CHECK_NE(sd, kNoSRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + B11 | B9 | addr.vencoding(); + Emit(encoding); +} + + +void Arm32Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(dd, kNoDRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | B20 | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + B11 | B9 | B8 | addr.vencoding(); + Emit(encoding); +} + + +void Arm32Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC); + CHECK_NE(dd, kNoDRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + B11 | B9 | B8 | addr.vencoding(); + Emit(encoding); +} + + +void Arm32Assembler::vpushs(SRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond); +} + + +void Arm32Assembler::vpushd(DRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond); +} + + +void Arm32Assembler::vpops(SRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond); +} + + +void Arm32Assembler::vpopd(DRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond); +} + + +void Arm32Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) { + CHECK_NE(cond, kNoCondition); + CHECK_GT(nregs, 0); + uint32_t D; + uint32_t Vd; + if (dbl) { + // Encoded as D:Vd. + D = (reg >> 4) & 1; + Vd = reg & 0b1111; + } else { + // Encoded as Vd:D. + D = reg & 1; + Vd = (reg >> 1) & 0b1111; + } + int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 | + B11 | B9 | + (dbl ? B8 : 0) | + (push ? B24 : (B23 | B20)) | + static_cast<int32_t>(cond) << kConditionShift | + nregs << (dbl ? 1 : 0) | + D << 22 | + Vd << 12; + Emit(encoding); +} + + +void Arm32Assembler::EmitVFPsss(Condition cond, int32_t opcode, + SRegister sd, SRegister sn, SRegister sm) { + CHECK_NE(sd, kNoSRegister); + CHECK_NE(sn, kNoSRegister); + CHECK_NE(sm, kNoSRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | opcode | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sn) >> 1)*B16) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + ((static_cast<int32_t>(sn) & 1)*B7) | + ((static_cast<int32_t>(sm) & 1)*B5) | + (static_cast<int32_t>(sm) >> 1); + Emit(encoding); +} + + +void Arm32Assembler::EmitVFPddd(Condition cond, int32_t opcode, + DRegister dd, DRegister dn, DRegister dm) { + CHECK_NE(dd, kNoDRegister); + CHECK_NE(dn, kNoDRegister); + CHECK_NE(dm, kNoDRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | B8 | opcode | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dn) & 0xf)*B16) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + ((static_cast<int32_t>(dn) >> 4)*B7) | + ((static_cast<int32_t>(dm) >> 4)*B5) | + (static_cast<int32_t>(dm) & 0xf); + Emit(encoding); +} + + +void Arm32Assembler::EmitVFPsd(Condition cond, int32_t opcode, + SRegister sd, DRegister dm) { + CHECK_NE(sd, kNoSRegister); + CHECK_NE(dm, kNoDRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | opcode | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + ((static_cast<int32_t>(dm) >> 4)*B5) | + (static_cast<int32_t>(dm) & 0xf); + Emit(encoding); +} + + +void Arm32Assembler::EmitVFPds(Condition cond, int32_t opcode, + DRegister dd, SRegister sm) { + CHECK_NE(dd, kNoDRegister); + CHECK_NE(sm, kNoSRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | opcode | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + ((static_cast<int32_t>(sm) & 1)*B5) | + (static_cast<int32_t>(sm) >> 1); + Emit(encoding); +} + + +void Arm32Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Do not use Lsl if no shift is wanted. + mov(rd, ShifterOperand(rm, LSL, shift_imm), cond); +} + + +void Arm32Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted. + if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. + mov(rd, ShifterOperand(rm, LSR, shift_imm), cond); +} + + +void Arm32Assembler::Asr(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted. + if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. + mov(rd, ShifterOperand(rm, ASR, shift_imm), cond); +} + + +void Arm32Assembler::Ror(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Use Rrx instruction. + mov(rd, ShifterOperand(rm, ROR, shift_imm), cond); +} + +void Arm32Assembler::Rrx(Register rd, Register rm, Condition cond) { + mov(rd, ShifterOperand(rm, ROR, 0), cond); +} + + +void Arm32Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 | + (static_cast<int32_t>(PC)*B12) | + B11 | B9 | B4; + Emit(encoding); +} + + +void Arm32Assembler::svc(uint32_t imm24) { + CHECK(IsUint(24, imm24)) << imm24; + int32_t encoding = (AL << kConditionShift) | B27 | B26 | B25 | B24 | imm24; + Emit(encoding); +} + + +void Arm32Assembler::bkpt(uint16_t imm16) { + int32_t encoding = (AL << kConditionShift) | B24 | B21 | + ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); + Emit(encoding); +} + + +void Arm32Assembler::blx(Register rm, Condition cond) { + CHECK_NE(rm, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B24 | B21 | (0xfff << 8) | B5 | B4 | + (static_cast<int32_t>(rm) << kRmShift); + Emit(encoding); +} + + +void Arm32Assembler::bx(Register rm, Condition cond) { + CHECK_NE(rm, kNoRegister); + CHECK_NE(cond, kNoCondition); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B24 | B21 | (0xfff << 8) | B4 | + (static_cast<int32_t>(rm) << kRmShift); + Emit(encoding); +} + + +void Arm32Assembler::Push(Register rd, Condition cond) { + str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond); +} + + +void Arm32Assembler::Pop(Register rd, Condition cond) { + ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond); +} + + +void Arm32Assembler::PushList(RegList regs, Condition cond) { + stm(DB_W, SP, regs, cond); +} + + +void Arm32Assembler::PopList(RegList regs, Condition cond) { + ldm(IA_W, SP, regs, cond); +} + + +void Arm32Assembler::Mov(Register rd, Register rm, Condition cond) { + if (rd != rm) { + mov(rd, ShifterOperand(rm), cond); + } +} + + +void Arm32Assembler::Bind(Label* label) { + CHECK(!label->IsBound()); + int bound_pc = buffer_.Size(); + while (label->IsLinked()) { + int32_t position = label->Position(); + int32_t next = buffer_.Load<int32_t>(position); + int32_t encoded = Arm32Assembler::EncodeBranchOffset(bound_pc - position, next); + buffer_.Store<int32_t>(position, encoded); + label->position_ = Arm32Assembler::DecodeBranchOffset(next); + } + label->BindTo(bound_pc); +} + + +int32_t Arm32Assembler::EncodeBranchOffset(int offset, int32_t inst) { + // The offset is off by 8 due to the way the ARM CPUs read PC. + offset -= 8; + CHECK_ALIGNED(offset, 4); + CHECK(IsInt(POPCOUNT(kBranchOffsetMask), offset)) << offset; + + // Properly preserve only the bits supported in the instruction. + offset >>= 2; + offset &= kBranchOffsetMask; + return (inst & ~kBranchOffsetMask) | offset; +} + + +int Arm32Assembler::DecodeBranchOffset(int32_t inst) { + // Sign-extend, left-shift by 2, then add 8. + return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8); +} + + +void Arm32Assembler::AddConstant(Register rd, int32_t value, Condition cond) { + AddConstant(rd, rd, value, cond); +} + + +void Arm32Assembler::AddConstant(Register rd, Register rn, int32_t value, + Condition cond) { + if (value == 0) { + if (rd != rn) { + mov(rd, ShifterOperand(rn), cond); + } + return; + } + // We prefer to select the shorter code sequence rather than selecting add for + // positive values and sub for negatives ones, which would slightly improve + // the readability of generated code for some constants. + ShifterOperand shifter_op; + if (ShifterOperand::CanHoldArm(value, &shifter_op)) { + add(rd, rn, shifter_op, cond); + } else if (ShifterOperand::CanHoldArm(-value, &shifter_op)) { + sub(rd, rn, shifter_op, cond); + } else { + CHECK(rn != IP); + if (ShifterOperand::CanHoldArm(~value, &shifter_op)) { + mvn(IP, shifter_op, cond); + add(rd, rn, ShifterOperand(IP), cond); + } else if (ShifterOperand::CanHoldArm(~(-value), &shifter_op)) { + mvn(IP, shifter_op, cond); + sub(rd, rn, ShifterOperand(IP), cond); + } else { + movw(IP, Low16Bits(value), cond); + uint16_t value_high = High16Bits(value); + if (value_high != 0) { + movt(IP, value_high, cond); + } + add(rd, rn, ShifterOperand(IP), cond); + } + } +} + + +void Arm32Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value, + Condition cond) { + ShifterOperand shifter_op; + if (ShifterOperand::CanHoldArm(value, &shifter_op)) { + adds(rd, rn, shifter_op, cond); + } else if (ShifterOperand::CanHoldArm(-value, &shifter_op)) { + subs(rd, rn, shifter_op, cond); + } else { + CHECK(rn != IP); + if (ShifterOperand::CanHoldArm(~value, &shifter_op)) { + mvn(IP, shifter_op, cond); + adds(rd, rn, ShifterOperand(IP), cond); + } else if (ShifterOperand::CanHoldArm(~(-value), &shifter_op)) { + mvn(IP, shifter_op, cond); + subs(rd, rn, ShifterOperand(IP), cond); + } else { + movw(IP, Low16Bits(value), cond); + uint16_t value_high = High16Bits(value); + if (value_high != 0) { + movt(IP, value_high, cond); + } + adds(rd, rn, ShifterOperand(IP), cond); + } + } +} + + +void Arm32Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { + ShifterOperand shifter_op; + if (ShifterOperand::CanHoldArm(value, &shifter_op)) { + mov(rd, shifter_op, cond); + } else if (ShifterOperand::CanHoldArm(~value, &shifter_op)) { + mvn(rd, shifter_op, cond); + } else { + movw(rd, Low16Bits(value), cond); + uint16_t value_high = High16Bits(value); + if (value_high != 0) { + movt(rd, value_high, cond); + } + } +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldLoadOffsetArm. +void Arm32Assembler::LoadFromOffset(LoadOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldLoadOffsetArm(type, offset)) { + CHECK(base != IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldLoadOffsetArm(type, offset)); + switch (type) { + case kLoadSignedByte: + ldrsb(reg, Address(base, offset), cond); + break; + case kLoadUnsignedByte: + ldrb(reg, Address(base, offset), cond); + break; + case kLoadSignedHalfword: + ldrsh(reg, Address(base, offset), cond); + break; + case kLoadUnsignedHalfword: + ldrh(reg, Address(base, offset), cond); + break; + case kLoadWord: + ldr(reg, Address(base, offset), cond); + break; + case kLoadWordPair: + ldrd(reg, Address(base, offset), cond); + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldLoadOffsetArm, as expected by JIT::GuardedLoadFromOffset. +void Arm32Assembler::LoadSFromOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldLoadOffsetArm(kLoadSWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldLoadOffsetArm(kLoadSWord, offset)); + vldrs(reg, Address(base, offset), cond); +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldLoadOffsetArm, as expected by JIT::GuardedLoadFromOffset. +void Arm32Assembler::LoadDFromOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldLoadOffsetArm(kLoadDWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldLoadOffsetArm(kLoadDWord, offset)); + vldrd(reg, Address(base, offset), cond); +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldStoreOffsetArm. +void Arm32Assembler::StoreToOffset(StoreOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldStoreOffsetArm(type, offset)) { + CHECK(reg != IP); + CHECK(base != IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldStoreOffsetArm(type, offset)); + switch (type) { + case kStoreByte: + strb(reg, Address(base, offset), cond); + break; + case kStoreHalfword: + strh(reg, Address(base, offset), cond); + break; + case kStoreWord: + str(reg, Address(base, offset), cond); + break; + case kStoreWordPair: + strd(reg, Address(base, offset), cond); + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldStoreOffsetArm, as expected by JIT::GuardedStoreToOffset. +void Arm32Assembler::StoreSToOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldStoreOffsetArm(kStoreSWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldStoreOffsetArm(kStoreSWord, offset)); + vstrs(reg, Address(base, offset), cond); +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldStoreOffsetArm, as expected by JIT::GuardedStoreSToOffset. +void Arm32Assembler::StoreDToOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldStoreOffsetArm(kStoreDWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldStoreOffsetArm(kStoreDWord, offset)); + vstrd(reg, Address(base, offset), cond); +} + + +void Arm32Assembler::MemoryBarrier(ManagedRegister mscratch) { + CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12); +#if ANDROID_SMP != 0 + int32_t encoding = 0xf57ff05f; // dmb + Emit(encoding); +#endif +} + + +void Arm32Assembler::cbz(Register rn, Label* target) { + LOG(FATAL) << "cbz is not supported on ARM32"; +} + + +void Arm32Assembler::cbnz(Register rn, Label* target) { + LOG(FATAL) << "cbnz is not supported on ARM32"; +} + + +void Arm32Assembler::CompareAndBranchIfZero(Register r, Label* label) { + cmp(r, ShifterOperand(0)); + b(label, EQ); +} + + +void Arm32Assembler::CompareAndBranchIfNonZero(Register r, Label* label) { + cmp(r, ShifterOperand(0)); + b(label, NE); +} + + +} // namespace arm +} // namespace art diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h new file mode 100644 index 0000000..7a0fce2 --- /dev/null +++ b/compiler/utils/arm/assembler_arm32.h @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM32_H_ +#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM32_H_ + +#include <vector> + +#include "base/logging.h" +#include "constants_arm.h" +#include "utils/arm/managed_register_arm.h" +#include "utils/arm/assembler_arm.h" +#include "offsets.h" +#include "utils.h" + +namespace art { +namespace arm { + +class Arm32Assembler FINAL : public ArmAssembler { + public: + Arm32Assembler() { + } + virtual ~Arm32Assembler() {} + + bool IsThumb() const OVERRIDE { + return false; + } + + // Data-processing instructions. + void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void tst(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void teq(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void mov(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void movs(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + // Miscellaneous data-processing instructions. + void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void movw(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; + void movt(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; + + // Multiply instructions. + void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + void mla(Register rd, Register rn, Register rm, Register ra, + Condition cond = AL) OVERRIDE; + void mls(Register rd, Register rn, Register rm, Register ra, + Condition cond = AL) OVERRIDE; + void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, + Condition cond = AL) OVERRIDE; + + void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + + // Load/store instructions. + void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void str(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void strb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void strh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrsb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void ldrsh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void strd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldm(BlockAddressMode am, Register base, + RegList regs, Condition cond = AL) OVERRIDE; + void stm(BlockAddressMode am, Register base, + RegList regs, Condition cond = AL) OVERRIDE; + + void ldrex(Register rd, Register rn, Condition cond = AL) OVERRIDE; + void strex(Register rd, Register rt, Register rn, Condition cond = AL) OVERRIDE; + + // Miscellaneous instructions. + void clrex(Condition cond = AL) OVERRIDE; + void nop(Condition cond = AL) OVERRIDE; + + // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. + void bkpt(uint16_t imm16) OVERRIDE; + void svc(uint32_t imm24) OVERRIDE; + + void cbz(Register rn, Label* target) OVERRIDE; + void cbnz(Register rn, Label* target) OVERRIDE; + + // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles). + void vmovsr(SRegister sn, Register rt, Condition cond = AL) OVERRIDE; + void vmovrs(Register rt, SRegister sn, Condition cond = AL) OVERRIDE; + void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) OVERRIDE; + void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) OVERRIDE; + void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) OVERRIDE; + void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) OVERRIDE; + void vmovs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vmovd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + + // Returns false if the immediate cannot be encoded. + bool vmovs(SRegister sd, float s_imm, Condition cond = AL) OVERRIDE; + bool vmovd(DRegister dd, double d_imm, Condition cond = AL) OVERRIDE; + + void vldrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE; + void vstrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE; + void vldrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE; + void vstrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE; + + void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + + void vabss(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vabsd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + void vnegs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vnegd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + + void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE; + + void vcmps(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcmpsz(SRegister sd, Condition cond = AL) OVERRIDE; + void vcmpdz(DRegister dd, Condition cond = AL) OVERRIDE; + void vmstat(Condition cond = AL) OVERRIDE; // VMRS APSR_nzcv, FPSCR + + void vpushs(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; + void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE; + void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; + void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE; + + // Branch instructions. + void b(Label* label, Condition cond = AL); + void bl(Label* label, Condition cond = AL); + void blx(Register rm, Condition cond = AL) OVERRIDE; + void bx(Register rm, Condition cond = AL) OVERRIDE; + void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Rrx(Register rd, Register rm, Condition cond = AL); + + void Push(Register rd, Condition cond = AL) OVERRIDE; + void Pop(Register rd, Condition cond = AL) OVERRIDE; + + void PushList(RegList regs, Condition cond = AL) OVERRIDE; + void PopList(RegList regs, Condition cond = AL) OVERRIDE; + + void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE; + + void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE; + void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE; + + + // Macros. + // Add signed constant value to rd. May clobber IP. + void AddConstant(Register rd, int32_t value, Condition cond = AL) OVERRIDE; + void AddConstant(Register rd, Register rn, int32_t value, + Condition cond = AL) OVERRIDE; + void AddConstantSetFlags(Register rd, Register rn, int32_t value, + Condition cond = AL) OVERRIDE; + void AddConstantWithCarry(Register rd, Register rn, int32_t value, + Condition cond = AL) {} + + // Load and Store. May clobber IP. + void LoadImmediate(Register rd, int32_t value, Condition cond = AL) OVERRIDE; + void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {} + void LoadDImmediate(DRegister dd, double value, + Register scratch, Condition cond = AL) {} + void MarkExceptionHandler(Label* label) OVERRIDE; + void LoadFromOffset(LoadOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void StoreToOffset(StoreOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void LoadSFromOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void StoreSToOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void LoadDFromOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void StoreDToOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + + + static bool IsInstructionForExceptionHandling(uword pc); + + // Emit data (e.g. encoded instruction or immediate) to the + // instruction stream. + void Emit(int32_t value); + void Bind(Label* label) OVERRIDE; + + void MemoryBarrier(ManagedRegister scratch) OVERRIDE; + + private: + void EmitType01(Condition cond, + int type, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so); + + void EmitType5(Condition cond, int offset, bool link); + + void EmitMemOp(Condition cond, + bool load, + bool byte, + Register rd, + const Address& ad); + + void EmitMemOpAddressMode3(Condition cond, + int32_t mode, + Register rd, + const Address& ad); + + void EmitMultiMemOp(Condition cond, + BlockAddressMode am, + bool load, + Register base, + RegList regs); + + void EmitShiftImmediate(Condition cond, + Shift opcode, + Register rd, + Register rm, + const ShifterOperand& so); + + void EmitShiftRegister(Condition cond, + Shift opcode, + Register rd, + Register rm, + const ShifterOperand& so); + + void EmitMulOp(Condition cond, + int32_t opcode, + Register rd, + Register rn, + Register rm, + Register rs); + + void EmitVFPsss(Condition cond, + int32_t opcode, + SRegister sd, + SRegister sn, + SRegister sm); + + void EmitVFPddd(Condition cond, + int32_t opcode, + DRegister dd, + DRegister dn, + DRegister dm); + + void EmitVFPsd(Condition cond, + int32_t opcode, + SRegister sd, + DRegister dm); + + void EmitVFPds(Condition cond, + int32_t opcode, + DRegister dd, + SRegister sm); + + void EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond); + + void EmitBranch(Condition cond, Label* label, bool link); + static int32_t EncodeBranchOffset(int offset, int32_t inst); + static int DecodeBranchOffset(int32_t inst); + int32_t EncodeTstOffset(int offset, int32_t inst); + int DecodeTstOffset(int32_t inst); +}; + +} // namespace arm +} // namespace art + +#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM32_H_ diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc new file mode 100644 index 0000000..703d68e --- /dev/null +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -0,0 +1,2363 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assembler_thumb2.h" + +#include "base/logging.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "offsets.h" +#include "thread.h" +#include "utils.h" + +namespace art { +namespace arm { + +void Thumb2Assembler::and_(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, AND, 0, rn, rd, so); +} + + +void Thumb2Assembler::eor(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, EOR, 0, rn, rd, so); +} + + +void Thumb2Assembler::sub(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, SUB, 0, rn, rd, so); +} + + +void Thumb2Assembler::rsb(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, RSB, 0, rn, rd, so); +} + + +void Thumb2Assembler::rsbs(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, RSB, 1, rn, rd, so); +} + + +void Thumb2Assembler::add(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, ADD, 0, rn, rd, so); +} + + +void Thumb2Assembler::adds(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, ADD, 1, rn, rd, so); +} + + +void Thumb2Assembler::subs(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, SUB, 1, rn, rd, so); +} + + +void Thumb2Assembler::adc(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, ADC, 0, rn, rd, so); +} + + +void Thumb2Assembler::sbc(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, SBC, 0, rn, rd, so); +} + + +void Thumb2Assembler::rsc(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, RSC, 0, rn, rd, so); +} + + +void Thumb2Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) { + CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker. + EmitDataProcessing(cond, TST, 1, rn, R0, so); +} + + +void Thumb2Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) { + CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker. + EmitDataProcessing(cond, TEQ, 1, rn, R0, so); +} + + +void Thumb2Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, CMP, 1, rn, R0, so); +} + + +void Thumb2Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, CMN, 1, rn, R0, so); +} + + +void Thumb2Assembler::orr(Register rd, Register rn, + const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, ORR, 0, rn, rd, so); +} + + +void Thumb2Assembler::orrs(Register rd, Register rn, + const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, ORR, 1, rn, rd, so); +} + + +void Thumb2Assembler::mov(Register rd, const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, MOV, 0, R0, rd, so); +} + + +void Thumb2Assembler::movs(Register rd, const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, MOV, 1, R0, rd, so); +} + + +void Thumb2Assembler::bic(Register rd, Register rn, const ShifterOperand& so, + Condition cond) { + EmitDataProcessing(cond, BIC, 0, rn, rd, so); +} + + +void Thumb2Assembler::mvn(Register rd, const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, MVN, 0, R0, rd, so); +} + + +void Thumb2Assembler::mvns(Register rd, const ShifterOperand& so, Condition cond) { + EmitDataProcessing(cond, MVN, 1, R0, rd, so); +} + + +void Thumb2Assembler::mul(Register rd, Register rn, Register rm, Condition cond) { + if (rd == rm && !IsHighRegister(rd) && !IsHighRegister(rn) && !force_32bit_) { + // 16 bit. + int16_t encoding = B14 | B9 | B8 | B6 | + rn << 3 | rd; + Emit16(encoding); + } else { + // 32 bit. + uint32_t op1 = 0b000; + uint32_t op2 = 0b00; + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | + op1 << 20 | + B15 | B14 | B13 | B12 | + op2 << 4 | + static_cast<uint32_t>(rd) << 8 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rm); + + Emit32(encoding); + } +} + + +void Thumb2Assembler::mla(Register rd, Register rn, Register rm, Register ra, + Condition cond) { + uint32_t op1 = 0b000; + uint32_t op2 = 0b00; + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | + op1 << 20 | + op2 << 4 | + static_cast<uint32_t>(rd) << 8 | + static_cast<uint32_t>(ra) << 12 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rm); + + Emit32(encoding); +} + + +void Thumb2Assembler::mls(Register rd, Register rn, Register rm, Register ra, + Condition cond) { + uint32_t op1 = 0b000; + uint32_t op2 = 0b01; + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | + op1 << 20 | + op2 << 4 | + static_cast<uint32_t>(rd) << 8 | + static_cast<uint32_t>(ra) << 12 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rm); + + Emit32(encoding); +} + + +void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn, + Register rm, Condition cond) { + uint32_t op1 = 0b010; + uint32_t op2 = 0b0000; + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | + op1 << 20 | + op2 << 4 | + static_cast<uint32_t>(rd_lo) << 12 | + static_cast<uint32_t>(rd_hi) << 8 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rm); + + Emit32(encoding); +} + + +void Thumb2Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) { + uint32_t op1 = 0b001; + uint32_t op2 = 0b1111; + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B20 | + op1 << 20 | + op2 << 4 | + 0xf << 12 | + static_cast<uint32_t>(rd) << 8 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rm); + + Emit32(encoding); +} + + +void Thumb2Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) { + uint32_t op1 = 0b001; + uint32_t op2 = 0b1111; + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B21 | B20 | + op1 << 20 | + op2 << 4 | + 0xf << 12 | + static_cast<uint32_t>(rd) << 8 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rm); + + Emit32(encoding); +} + + +void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, true, false, false, false, rd, ad); +} + + +void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, false, false, false, false, rd, ad); +} + + +void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, true, true, false, false, rd, ad); +} + + +void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, false, true, false, false, rd, ad); +} + + +void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, true, false, true, false, rd, ad); +} + + +void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, false, false, true, false, rd, ad); +} + + +void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, true, true, false, true, rd, ad); +} + + +void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) { + EmitLoadStore(cond, true, false, true, true, rd, ad); +} + + +void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) { + CHECK_EQ(rd % 2, 0); + // This is different from other loads. The encoding is like ARM. + int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 | + static_cast<int32_t>(rd) << 12 | + (static_cast<int32_t>(rd) + 1) << 8 | + ad.encodingThumbLdrdStrd(); + Emit32(encoding); +} + + +void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) { + CHECK_EQ(rd % 2, 0); + // This is different from other loads. The encoding is like ARM. + int32_t encoding = B31 | B30 | B29 | B27 | B22 | + static_cast<int32_t>(rd) << 12 | + (static_cast<int32_t>(rd) + 1) << 8 | + ad.encodingThumbLdrdStrd(); + Emit32(encoding); +} + + +void Thumb2Assembler::ldm(BlockAddressMode am, + Register base, + RegList regs, + Condition cond) { + if (__builtin_popcount(regs) == 1) { + // Thumb doesn't support one reg in the list. + // Find the register number. + int reg = 0; + while (reg < 16) { + if ((regs & (1 << reg)) != 0) { + break; + } + ++reg; + } + CHECK_LT(reg, 16); + CHECK(am == DB_W); // Only writeback is supported. + ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond); + } else { + EmitMultiMemOp(cond, am, true, base, regs); + } +} + + +void Thumb2Assembler::stm(BlockAddressMode am, + Register base, + RegList regs, + Condition cond) { + if (__builtin_popcount(regs) == 1) { + // Thumb doesn't support one reg in the list. + // Find the register number. + int reg = 0; + while (reg < 16) { + if ((regs & (1 << reg)) != 0) { + break; + } + ++reg; + } + CHECK_LT(reg, 16); + CHECK(am == IA || am == IA_W); + Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset; + str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond); + } else { + EmitMultiMemOp(cond, am, false, base, regs); + } +} + + +bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) { + uint32_t imm32 = bit_cast<uint32_t, float>(s_imm); + if (((imm32 & ((1 << 19) - 1)) == 0) && + ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) || + (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) { + uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) | + ((imm32 >> 19) & ((1 << 6) -1)); + EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf), + sd, S0, S0); + return true; + } + return false; +} + + +bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) { + uint64_t imm64 = bit_cast<uint64_t, double>(d_imm); + if (((imm64 & ((1LL << 48) - 1)) == 0) && + ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) || + (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) { + uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) | + ((imm64 >> 48) & ((1 << 6) -1)); + EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf), + dd, D0, D0); + return true; + } + return false; +} + + +void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm); +} + + +void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B21 | B20, sd, sn, sm); +} + + +void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B21 | B20, dd, dn, dm); +} + + +void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm); +} + + +void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm); +} + + +void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B21, sd, sn, sm); +} + + +void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B21, dd, dn, dm); +} + + +void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, 0, sd, sn, sm); +} + + +void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, 0, dd, dn, dm); +} + + +void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B6, sd, sn, sm); +} + + +void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B6, dd, dn, dm); +} + + +void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm, + Condition cond) { + EmitVFPsss(cond, B23, sd, sn, sm); +} + + +void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm, + Condition cond) { + EmitVFPddd(cond, B23, dd, dn, dm); +} + + +void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm); +} + + +void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm); +} + + +void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm); +} + +void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm); +} + + +void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) { + EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm); +} + + +void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) { + EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm); +} + + +void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) { + EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm); +} + + +void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) { + EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm); +} + + +void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) { + EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm); +} + + +void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) { + EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm); +} + + +void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm); +} + + +void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm); +} + + +void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) { + EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0); +} + + +void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) { + EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0); +} + +void Thumb2Assembler::b(Label* label, Condition cond) { + EmitBranch(cond, label, false, false); +} + + +void Thumb2Assembler::bl(Label* label, Condition cond) { + CheckCondition(cond); + EmitBranch(cond, label, true, false); +} + + +void Thumb2Assembler::blx(Label* label) { + EmitBranch(AL, label, true, true); +} + + +void Thumb2Assembler::MarkExceptionHandler(Label* label) { + EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0)); + Label l; + b(&l); + EmitBranch(AL, label, false, false); + Bind(&l); +} + + +void Thumb2Assembler::Emit32(int32_t value) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + buffer_.Emit<int16_t>(value >> 16); + buffer_.Emit<int16_t>(value & 0xffff); +} + + +void Thumb2Assembler::Emit16(int16_t value) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + buffer_.Emit<int16_t>(value); +} + + +bool Thumb2Assembler::Is32BitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so) { + if (force_32bit_) { + return true; + } + + bool can_contain_high_register = opcode == MOV || opcode == ADD || opcode == SUB; + + if (IsHighRegister(rd) || IsHighRegister(rn)) { + if (can_contain_high_register) { + // There are high register instructions available for this opcode. + // However, there is no RRX available. + if (so.IsShift() && so.GetShift() == RRX) { + return true; + } + + // Check special case for SP relative ADD and SUB immediate. + if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) { + // If rn is SP and rd is a high register we need to use a 32 bit encoding. + if (rn == SP && rd != SP && IsHighRegister(rd)) { + return true; + } + + uint32_t imm = so.GetImmediate(); + // If the immediates are out of range use 32 bit. + if (rd == SP && rn == SP) { + if (imm > (1 << 9)) { // 9 bit immediate. + return true; + } + } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate. + if (imm > (1 << 10)) { + return true; + } + } else if (opcode == SUB && rd != SP && rn == SP) { + // SUB rd, SP, #imm is always 32 bit. + return true; + } + } + } + + // The ADD,SUB and MOV instructions that work with high registers don't have + // immediate variants. + if (so.IsImmediate()) { + return true; + } + } + + if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) { + return true; + } + + // Check for MOV with an ROR. + if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) { + if (so.GetImmediate() != 0) { + return true; + } + } + + bool rn_is_valid = true; + + // Check for single operand instructions and ADD/SUB. + switch (opcode) { + case CMP: + case MOV: + case TST: + case MVN: + rn_is_valid = false; // There is no Rn for these instructions. + break; + case TEQ: + return true; + break; + case ADD: + case SUB: + break; + default: + if (so.IsRegister() && rd != rn) { + return true; + } + } + + if (so.IsImmediate()) { + if (rn_is_valid && rn != rd) { + // The only thumb1 instruction with a register and an immediate are ADD and SUB. The + // immediate must be 3 bits. + if (opcode != ADD && opcode != SUB) { + return true; + } else { + // Check that the immediate is 3 bits for ADD and SUB. + if (so.GetImmediate() >= 8) { + return true; + } + } + } else { + // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits. + if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) { + return true; + } else { + if (so.GetImmediate() > 255) { + return true; + } + } + } + } + + // The instruction can be encoded in 16 bits. + return false; +} + + +void Thumb2Assembler::Emit32BitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so) { + uint8_t thumb_opcode = 0b11111111; + switch (opcode) { + case AND: thumb_opcode = 0b0000; break; + case EOR: thumb_opcode = 0b0100; break; + case SUB: thumb_opcode = 0b1101; break; + case RSB: thumb_opcode = 0b1110; break; + case ADD: thumb_opcode = 0b1000; break; + case ADC: thumb_opcode = 0b1010; break; + case SBC: thumb_opcode = 0b1011; break; + case RSC: break; + case TST: thumb_opcode = 0b0000; set_cc = true; rd = PC; break; + case TEQ: thumb_opcode = 0b0100; set_cc = true; rd = PC; break; + case CMP: thumb_opcode = 0b1101; set_cc = true; rd = PC; break; + case CMN: thumb_opcode = 0b1000; set_cc = true; rd = PC; break; + case ORR: thumb_opcode = 0b0010; break; + case MOV: thumb_opcode = 0b0010; rn = PC; break; + case BIC: thumb_opcode = 0b0001; break; + case MVN: thumb_opcode = 0b0011; rn = PC; break; + default: + break; + } + + if (thumb_opcode == 0b11111111) { + LOG(FATAL) << "Invalid thumb2 opcode " << opcode; + } + + int32_t encoding = 0; + if (so.IsImmediate()) { + // Check special cases. + if ((opcode == SUB || opcode == ADD) && rn == SP) { + // There are special ADD/SUB rd, SP, #imm12 instructions. + if (opcode == SUB) { + thumb_opcode = 0b0101; + } else { + thumb_opcode = 0; + } + uint32_t imm = so.GetImmediate(); + CHECK_LT(imm, (1u << 12)); + + uint32_t i = (imm >> 11) & 1; + uint32_t imm3 = (imm >> 8) & 0b111; + uint32_t imm8 = imm & 0xff; + + encoding = B31 | B30 | B29 | B28 | B25 | + B19 | B18 | B16 | + thumb_opcode << 21 | + rd << 8 | + i << 26 | + imm3 << 12 | + imm8; + } else { + // Modified immediate. + uint32_t imm = ModifiedImmediate(so.encodingThumb(2)); + if (imm == kInvalidModifiedImmediate) { + LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate"; + } + encoding = B31 | B30 | B29 | B28 | + thumb_opcode << 21 | + set_cc << 20 | + rn << 16 | + rd << 8 | + imm; + } + } else if (so.IsRegister()) { + // Register (possibly shifted) + encoding = B31 | B30 | B29 | B27 | B25 | + thumb_opcode << 21 | + set_cc << 20 | + rn << 16 | + rd << 8 | + so.encodingThumb(2); + } + Emit32(encoding); +} + + +void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so) { + if (opcode == ADD || opcode == SUB) { + Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so); + return; + } + uint8_t thumb_opcode = 0b11111111; + // Thumb1. + uint8_t dp_opcode = 0b01; + uint8_t opcode_shift = 6; + uint8_t rd_shift = 0; + uint8_t rn_shift = 3; + uint8_t immediate_shift = 0; + bool use_immediate = false; + uint8_t immediate = 0; + + if (opcode == MOV && so.IsRegister() && so.IsShift()) { + // Convert shifted mov operand2 into 16 bit opcodes. + dp_opcode = 0; + opcode_shift = 11; + + use_immediate = true; + immediate = so.GetImmediate(); + immediate_shift = 6; + + rn = so.GetRegister(); + + switch (so.GetShift()) { + case LSL: thumb_opcode = 0b00; break; + case LSR: thumb_opcode = 0b01; break; + case ASR: thumb_opcode = 0b10; break; + case ROR: + // ROR doesn't allow immediates. + thumb_opcode = 0b111; + dp_opcode = 0b01; + opcode_shift = 6; + use_immediate = false; + break; + case RRX: break; + default: + break; + } + } else { + if (so.IsImmediate()) { + use_immediate = true; + immediate = so.GetImmediate(); + } + + switch (opcode) { + case AND: thumb_opcode = 0b0000; break; + case EOR: thumb_opcode = 0b0001; break; + case SUB: break; + case RSB: thumb_opcode = 0b1001; break; + case ADD: break; + case ADC: thumb_opcode = 0b0101; break; + case SBC: thumb_opcode = 0b0110; break; + case RSC: break; + case TST: thumb_opcode = 0b1000; rn = so.GetRegister(); break; + case TEQ: break; + case CMP: + if (use_immediate) { + // T2 encoding. + dp_opcode = 0; + opcode_shift = 11; + thumb_opcode = 0b101; + rd_shift = 8; + rn_shift = 8; + } else { + thumb_opcode = 0b1010; + rn = so.GetRegister(); + } + + break; + case CMN: thumb_opcode = 0b1011; rn = so.GetRegister(); break; + case ORR: thumb_opcode = 0b1100; break; + case MOV: + dp_opcode = 0; + if (use_immediate) { + // T2 encoding. + opcode_shift = 11; + thumb_opcode = 0b100; + rd_shift = 8; + rn_shift = 8; + } else { + rn = so.GetRegister(); + if (IsHighRegister(rn) || IsHighRegister(rd)) { + // Special mov for high registers. + dp_opcode = 0b01; + opcode_shift = 7; + // Put the top bit of rd into the bottom bit of the opcode. + thumb_opcode = 0b0001100 | static_cast<uint32_t>(rd) >> 3; + rd = static_cast<Register>(static_cast<uint32_t>(rd) & 0b111); + } else { + thumb_opcode = 0; + } + } + break; + case BIC: thumb_opcode = 0b1110; break; + case MVN: thumb_opcode = 0b1111; rn = so.GetRegister(); break; + default: + break; + } + } + + if (thumb_opcode == 0b11111111) { + LOG(FATAL) << "Invalid thumb1 opcode " << opcode; + } + + int16_t encoding = dp_opcode << 14 | + (thumb_opcode << opcode_shift) | + rd << rd_shift | + rn << rn_shift | + (use_immediate ? (immediate << immediate_shift) : 0); + + Emit16(encoding); +} + + +// ADD and SUB are complex enough to warrant their own emitter. +void Thumb2Assembler::Emit16BitAddSub(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so) { + uint8_t dp_opcode = 0; + uint8_t opcode_shift = 6; + uint8_t rd_shift = 0; + uint8_t rn_shift = 3; + uint8_t immediate_shift = 0; + bool use_immediate = false; + uint8_t immediate = 0; + uint8_t thumb_opcode;; + + if (so.IsImmediate()) { + use_immediate = true; + immediate = so.GetImmediate(); + } + + switch (opcode) { + case ADD: + if (so.IsRegister()) { + Register rm = so.GetRegister(); + if (rn == rd) { + // Can use T2 encoding (allows 4 bit registers) + dp_opcode = 0b01; + opcode_shift = 10; + thumb_opcode = 0b0001; + // Make Rn also contain the top bit of rd. + rn = static_cast<Register>(static_cast<uint32_t>(rm) | + (static_cast<uint32_t>(rd) & 0b1000) << 1); + rd = static_cast<Register>(static_cast<uint32_t>(rd) & 0b111); + } else { + // T1. + opcode_shift = 9; + thumb_opcode = 0b01100; + immediate = static_cast<uint32_t>(so.GetRegister()); + use_immediate = true; + immediate_shift = 6; + } + } else { + // Immediate. + if (rd == SP && rn == SP) { + // ADD sp, sp, #imm + dp_opcode = 0b10; + thumb_opcode = 0b11; + opcode_shift = 12; + CHECK_LT(immediate, (1 << 9)); + CHECK_EQ((immediate & 0b11), 0); + + // Remove rd and rn from instruction by orring it with immed and clearing bits. + rn = R0; + rd = R0; + rd_shift = 0; + rn_shift = 0; + immediate >>= 2; + } else if (rd != SP && rn == SP) { + // ADD rd, SP, #imm + dp_opcode = 0b10; + thumb_opcode = 0b101; + opcode_shift = 11; + CHECK_LT(immediate, (1 << 10)); + CHECK_EQ((immediate & 0b11), 0); + + // Remove rn from instruction. + rn = R0; + rn_shift = 0; + rd_shift = 8; + immediate >>= 2; + } else if (rn != rd) { + // Must use T1. + opcode_shift = 9; + thumb_opcode = 0b01110; + immediate_shift = 6; + } else { + // T2 encoding. + opcode_shift = 11; + thumb_opcode = 0b110; + rd_shift = 8; + rn_shift = 8; + } + } + break; + + case SUB: + if (so.IsRegister()) { + // T1. + opcode_shift = 9; + thumb_opcode = 0b01101; + immediate = static_cast<uint32_t>(so.GetRegister()); + use_immediate = true; + immediate_shift = 6; + } else { + if (rd == SP && rn == SP) { + // SUB sp, sp, #imm + dp_opcode = 0b10; + thumb_opcode = 0b1100001; + opcode_shift = 7; + CHECK_LT(immediate, (1 << 9)); + CHECK_EQ((immediate & 0b11), 0); + + // Remove rd and rn from instruction by orring it with immed and clearing bits. + rn = R0; + rd = R0; + rd_shift = 0; + rn_shift = 0; + immediate >>= 2; + } else if (rn != rd) { + // Must use T1. + opcode_shift = 9; + thumb_opcode = 0b01111; + immediate_shift = 6; + } else { + // T2 encoding. + opcode_shift = 11; + thumb_opcode = 0b111; + rd_shift = 8; + rn_shift = 8; + } + } + break; + default: + LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode; + return; + } + + int16_t encoding = dp_opcode << 14 | + (thumb_opcode << opcode_shift) | + rd << rd_shift | + rn << rn_shift | + (use_immediate ? (immediate << immediate_shift) : 0); + + Emit16(encoding); +} + + +void Thumb2Assembler::EmitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so) { + CHECK_NE(rd, kNoRegister); + CheckCondition(cond); + + if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) { + Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so); + } else { + Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so); + } +} + + +void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const { + bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink; + bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX; + int32_t offset = target_ - location_; + + if (size_ == k32Bit) { + int32_t encoding = B31 | B30 | B29 | B28 | B15; + if (link) { + // BL or BLX immediate. + encoding |= B14; + if (!x) { + encoding |= B12; + } else { + // Bottom bit of offset must be 0. + CHECK_EQ((offset & 1), 0); + } + } else { + if (x) { + LOG(FATAL) << "Invalid use of BX"; + } else { + if (cond_ == AL) { + // Can use the T4 encoding allowing a 24 bit offset. + if (!x) { + encoding |= B12; + } + } else { + // Must be T3 encoding with a 20 bit offset. + encoding |= cond_ << 22; + } + } + } + encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding); + buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16)); + buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff)); + } else { + if (IsCompareAndBranch()) { + offset -= 4; + uint16_t i = (offset >> 6) & 1; + uint16_t imm5 = (offset >> 1) & 0b11111; + int16_t encoding = B15 | B13 | B12 | + (type_ == kCompareAndBranchNonZero ? B11 : 0) | + static_cast<uint32_t>(rn_) | + B8 | + i << 9 | + imm5 << 3; + buffer->Store<int16_t>(location_, encoding); + } else { + offset -= 4; // Account for PC offset. + int16_t encoding; + // 16 bit. + if (cond_ == AL) { + encoding = B15 | B14 | B13 | + ((offset >> 1) & 0x7ff); + } else { + encoding = B15 | B14 | B12 | + cond_ << 8 | ((offset >> 1) & 0xff); + } + buffer->Store<int16_t>(location_, encoding); + } + } +} + + +uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) { + uint32_t location = buffer_.Size(); + + // This is always unresolved as it must be a forward branch. + Emit16(prev); // Previous link. + return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero, + location, rn); +} + + +// NOTE: this only support immediate offsets, not [rx,ry]. +// TODO: support [rx,ry] instructions. +void Thumb2Assembler::EmitLoadStore(Condition cond, + bool load, + bool byte, + bool half, + bool is_signed, + Register rd, + const Address& ad) { + CHECK_NE(rd, kNoRegister); + CheckCondition(cond); + bool must_be_32bit = force_32bit_; + if (IsHighRegister(rd)) { + must_be_32bit = true; + } + + Register rn = ad.GetRegister(); + if (IsHighRegister(rn) && rn != SP) { + must_be_32bit = true; + } + + if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) { + must_be_32bit = true; + } + + int32_t offset = ad.GetOffset(); + + // The 16 bit SP relative instruction can only have a 10 bit offset. + if (rn == SP && offset > 1024) { + must_be_32bit = true; + } + + if (byte) { + // 5 bit offset, no shift. + if (offset > 32) { + must_be_32bit = true; + } + } else if (half) { + // 6 bit offset, shifted by 1. + if (offset > 64) { + must_be_32bit = true; + } + } else { + // 7 bit offset, shifted by 2. + if (offset > 128) { + must_be_32bit = true; + } + } + + if (must_be_32bit) { + int32_t encoding = B31 | B30 | B29 | B28 | B27 | + (load ? B20 : 0) | + (is_signed ? B24 : 0) | + static_cast<uint32_t>(rd) << 12 | + ad.encodingThumb(2) | + (byte ? 0 : half ? B21 : B22); + Emit32(encoding); + } else { + // 16 bit thumb1. + uint8_t opA = 0; + bool sp_relative = false; + + if (byte) { + opA = 0b0111; + } else if (half) { + opA = 0b1000; + } else { + if (rn == SP) { + opA = 0b1001; + sp_relative = true; + } else { + opA = 0b0110; + } + } + int16_t encoding = opA << 12 | + (load ? B11 : 0); + + CHECK_GE(offset, 0); + if (sp_relative) { + // SP relative, 10 bit offset. + CHECK_LT(offset, 1024); + CHECK_EQ((offset & 0b11), 0); + encoding |= rd << 8 | offset >> 2; + } else { + // No SP relative. The offset is shifted right depending on + // the size of the load/store. + encoding |= static_cast<uint32_t>(rd); + + if (byte) { + // 5 bit offset, no shift. + CHECK_LT(offset, 32); + } else if (half) { + // 6 bit offset, shifted by 1. + CHECK_LT(offset, 64); + CHECK_EQ((offset & 0b1), 0); + offset >>= 1; + } else { + // 7 bit offset, shifted by 2. + CHECK_LT(offset, 128); + CHECK_EQ((offset & 0b11), 0); + offset >>= 2; + } + encoding |= rn << 3 | offset << 6; + } + + Emit16(encoding); + } +} + + +void Thumb2Assembler::EmitMultiMemOp(Condition cond, + BlockAddressMode am, + bool load, + Register base, + RegList regs) { + CHECK_NE(base, kNoRegister); + CheckCondition(cond); + bool must_be_32bit = force_32bit_; + + if ((regs & 0xff00) != 0) { + must_be_32bit = true; + } + + uint32_t w_bit = am == IA_W || am == DB_W || am == DA_W || am == IB_W; + // 16 bit always uses writeback. + if (!w_bit) { + must_be_32bit = true; + } + + if (must_be_32bit) { + uint32_t op = 0; + switch (am) { + case IA: + case IA_W: + op = 0b01; + break; + case DB: + case DB_W: + op = 0b10; + break; + case DA: + case IB: + case DA_W: + case IB_W: + LOG(FATAL) << "LDM/STM mode not supported on thumb: " << am; + } + if (load) { + // Cannot have SP in the list. + CHECK_EQ((regs & (1 << SP)), 0); + } else { + // Cannot have PC or SP in the list. + CHECK_EQ((regs & (1 << PC | 1 << SP)), 0); + } + int32_t encoding = B31 | B30 | B29 | B27 | + (op << 23) | + (load ? B20 : 0) | + base << 16 | + regs | + (w_bit << 21); + Emit32(encoding); + } else { + int16_t encoding = B15 | B14 | + (load ? B11 : 0) | + base << 8 | + regs; + Emit16(encoding); + } +} + + +void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) { + uint32_t pc = buffer_.Size(); + Branch::Type branch_type; + if (cond == AL) { + if (link) { + if (x) { + branch_type = Branch::kUnconditionalLinkX; // BLX. + } else { + branch_type = Branch::kUnconditionalLink; // BX. + } + } else { + branch_type = Branch::kUnconditional; // B. + } + } else { + branch_type = Branch::kConditional; // B<cond>. + } + + if (label->IsBound()) { + Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch. + + // The branch is to a bound label which means that it's a backwards branch. We know the + // current size of it so we can emit the appropriate space. Note that if it's a 16 bit + // branch the size may change if it so happens that other branches change size that change + // the distance to the target and that distance puts this branch over the limit for 16 bits. + if (size == Branch::k16Bit) { + Emit16(0); // Space for a 16 bit branch. + } else { + Emit32(0); // Space for a 32 bit branch. + } + } else { + // Branch is to an unbound label. Emit space for it. + uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch. + if (force_32bit_) { + Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link. + Emit16(0); // another 16 bits. + } else { + Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link. + } + label->LinkTo(branch_id); // Link to the branch ID. + } +} + + +void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rm, kNoRegister); + CheckCondition(cond); + CHECK_NE(rd, PC); + CHECK_NE(rm, PC); + int32_t encoding = B31 | B30 | B29 | B28 | B27 | + B25 | B23 | B21 | B20 | + static_cast<uint32_t>(rm) << 16 | + 0xf << 12 | + static_cast<uint32_t>(rd) << 8 | + B7 | + static_cast<uint32_t>(rm); + Emit32(encoding); +} + + +void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) { + CheckCondition(cond); + bool must_be_32bit = force_32bit_; + if (IsHighRegister(rd)|| imm16 >= 256u) { + must_be_32bit = true; + } + + if (must_be_32bit) { + // Use encoding T3. + uint32_t imm4 = (imm16 >> 12) & 0b1111; + uint32_t i = (imm16 >> 11) & 0b1; + uint32_t imm3 = (imm16 >> 8) & 0b111; + uint32_t imm8 = imm16 & 0xff; + int32_t encoding = B31 | B30 | B29 | B28 | + B25 | B22 | + static_cast<uint32_t>(rd) << 8 | + i << 26 | + imm4 << 16 | + imm3 << 12 | + imm8; + Emit32(encoding); + } else { + int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 | + imm16; + Emit16(encoding); + } +} + + +void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) { + CheckCondition(cond); + // Always 32 bits. + uint32_t imm4 = (imm16 >> 12) & 0b1111; + uint32_t i = (imm16 >> 11) & 0b1; + uint32_t imm3 = (imm16 >> 8) & 0b111; + uint32_t imm8 = imm16 & 0xff; + int32_t encoding = B31 | B30 | B29 | B28 | + B25 | B23 | B22 | + static_cast<uint32_t>(rd) << 8 | + i << 26 | + imm4 << 16 | + imm3 << 12 | + imm8; + Emit32(encoding); +} + + +void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) { + CHECK_NE(rn, kNoRegister); + CHECK_NE(rt, kNoRegister); + CheckCondition(cond); + CHECK_NE(rn, kNoRegister); + CHECK_NE(rt, kNoRegister); + CheckCondition(cond); + CHECK_LT(imm, (1u << 10)); + + int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rt) << 12 | + 0xf << 8 | + imm >> 2; + Emit32(encoding); +} + + +void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) { + ldrex(rt, rn, 0, cond); +} + + +void Thumb2Assembler::strex(Register rd, + Register rt, + Register rn, + uint16_t imm, + Condition cond) { + CHECK_NE(rn, kNoRegister); + CHECK_NE(rd, kNoRegister); + CHECK_NE(rt, kNoRegister); + CheckCondition(cond); + CHECK_LT(imm, (1u << 10)); + + int32_t encoding = B31 | B30 | B29 | B27 | B22 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rt) << 12 | + static_cast<uint32_t>(rd) << 8 | + imm >> 2; + Emit32(encoding); +} + + +void Thumb2Assembler::strex(Register rd, + Register rt, + Register rn, + Condition cond) { + strex(rd, rt, rn, 0, cond); +} + + +void Thumb2Assembler::clrex(Condition cond) { + CheckCondition(cond); + int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 | + B21 | B20 | + 0xf << 16 | + B15 | + 0xf << 8 | + B5 | + 0xf; + Emit32(encoding); +} + + +void Thumb2Assembler::nop(Condition cond) { + CheckCondition(cond); + int16_t encoding = B15 | B13 | B12 | + B11 | B10 | B9 | B8; + Emit16(encoding); +} + + +void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) { + CHECK_NE(sn, kNoSRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | + ((static_cast<int32_t>(sn) >> 1)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sn) & 1)*B7) | B4; + Emit32(encoding); +} + + +void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) { + CHECK_NE(sn, kNoSRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B20 | + ((static_cast<int32_t>(sn) >> 1)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sn) & 1)*B7) | B4; + Emit32(encoding); +} + + +void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2, + Condition cond) { + CHECK_NE(sm, kNoSRegister); + CHECK_NE(sm, S31); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sm) & 1)*B5) | B4 | + (static_cast<int32_t>(sm) >> 1); + Emit32(encoding); +} + + +void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm, + Condition cond) { + CHECK_NE(sm, kNoSRegister); + CHECK_NE(sm, S31); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CHECK_NE(rt, rt2); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | B20 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | + ((static_cast<int32_t>(sm) & 1)*B5) | B4 | + (static_cast<int32_t>(sm) >> 1); + Emit32(encoding); +} + + +void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2, + Condition cond) { + CHECK_NE(dm, kNoDRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 | + ((static_cast<int32_t>(dm) >> 4)*B5) | B4 | + (static_cast<int32_t>(dm) & 0xf); + Emit32(encoding); +} + + +void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm, + Condition cond) { + CHECK_NE(dm, kNoDRegister); + CHECK_NE(rt, kNoRegister); + CHECK_NE(rt, SP); + CHECK_NE(rt, PC); + CHECK_NE(rt2, kNoRegister); + CHECK_NE(rt2, SP); + CHECK_NE(rt2, PC); + CHECK_NE(rt, rt2); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B22 | B20 | + (static_cast<int32_t>(rt2)*B16) | + (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 | + ((static_cast<int32_t>(dm) >> 4)*B5) | B4 | + (static_cast<int32_t>(dm) & 0xf); + Emit32(encoding); +} + + +void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(sd, kNoSRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | B20 | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + B11 | B9 | addr.vencoding(); + Emit32(encoding); +} + + +void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC); + CHECK_NE(sd, kNoSRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + B11 | B9 | addr.vencoding(); + Emit32(encoding); +} + + +void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(dd, kNoDRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | B20 | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + B11 | B9 | B8 | addr.vencoding(); + Emit32(encoding); +} + + +void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) { + const Address& addr = static_cast<const Address&>(ad); + CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC); + CHECK_NE(dd, kNoDRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B24 | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + B11 | B9 | B8 | addr.vencoding(); + Emit32(encoding); +} + + +void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond); +} + + +void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond); +} + + +void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond); +} + + +void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) { + EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond); +} + + +void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) { + CheckCondition(cond); + + uint32_t D; + uint32_t Vd; + if (dbl) { + // Encoded as D:Vd. + D = (reg >> 4) & 1; + Vd = reg & 0b1111; + } else { + // Encoded as Vd:D. + D = reg & 1; + Vd = (reg >> 1) & 0b1111; + } + int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 | + B11 | B9 | + (dbl ? B8 : 0) | + (push ? B24 : (B23 | B20)) | + 0b1110 << 28 | + nregs << (dbl ? 1 : 0) | + D << 22 | + Vd << 12; + Emit32(encoding); +} + + +void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode, + SRegister sd, SRegister sn, SRegister sm) { + CHECK_NE(sd, kNoSRegister); + CHECK_NE(sn, kNoSRegister); + CHECK_NE(sm, kNoSRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | opcode | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sn) >> 1)*B16) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + ((static_cast<int32_t>(sn) & 1)*B7) | + ((static_cast<int32_t>(sm) & 1)*B5) | + (static_cast<int32_t>(sm) >> 1); + Emit32(encoding); +} + + +void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode, + DRegister dd, DRegister dn, DRegister dm) { + CHECK_NE(dd, kNoDRegister); + CHECK_NE(dn, kNoDRegister); + CHECK_NE(dm, kNoDRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | B8 | opcode | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dn) & 0xf)*B16) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + ((static_cast<int32_t>(dn) >> 4)*B7) | + ((static_cast<int32_t>(dm) >> 4)*B5) | + (static_cast<int32_t>(dm) & 0xf); + Emit32(encoding); +} + + +void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode, + SRegister sd, DRegister dm) { + CHECK_NE(sd, kNoSRegister); + CHECK_NE(dm, kNoDRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | opcode | + ((static_cast<int32_t>(sd) & 1)*B22) | + ((static_cast<int32_t>(sd) >> 1)*B12) | + ((static_cast<int32_t>(dm) >> 4)*B5) | + (static_cast<int32_t>(dm) & 0xf); + Emit32(encoding); +} + + +void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode, + DRegister dd, SRegister sm) { + CHECK_NE(dd, kNoDRegister); + CHECK_NE(sm, kNoSRegister); + CheckCondition(cond); + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B11 | B9 | opcode | + ((static_cast<int32_t>(dd) >> 4)*B22) | + ((static_cast<int32_t>(dd) & 0xf)*B12) | + ((static_cast<int32_t>(sm) & 1)*B5) | + (static_cast<int32_t>(sm) >> 1); + Emit32(encoding); +} + + +void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR. + CheckCondition(cond); + UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction"; +} + + +void Thumb2Assembler::svc(uint32_t imm8) { + CHECK(IsUint(8, imm8)) << imm8; + int16_t encoding = B15 | B14 | B12 | + B11 | B10 | B9 | B8 | + imm8; + Emit16(encoding); +} + + +void Thumb2Assembler::bkpt(uint16_t imm8) { + CHECK(IsUint(8, imm8)) << imm8; + int16_t encoding = B15 | B13 | B12 | + B11 | B10 | B9 | + imm8; + Emit16(encoding); +} + +// Convert the given IT state to a mask bit given bit 0 of the first +// condition and a shift position. +static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) { + switch (s) { + case kItOmitted: return 1 << shift; + case kItThen: return firstcond0 << shift; + case kItElse: return !firstcond0 << shift; + } + return 0; +} + + +// Set the IT condition in the given position for the given state. This is used +// to check that conditional instructions match the preceding IT statement. +void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) { + switch (s) { + case kItOmitted: it_conditions_[index] = AL; break; + case kItThen: it_conditions_[index] = cond; break; + case kItElse: + it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1); + break; + } +} + + +void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) { + CheckCondition(AL); // Not allowed in IT block. + uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1; + + // All conditions to AL. + for (uint8_t i = 0; i < 4; ++i) { + it_conditions_[i] = AL; + } + + SetItCondition(kItThen, firstcond, 0); + uint8_t mask = ToItMask(i1, firstcond0, 3); + SetItCondition(i1, firstcond, 1); + + if (i1 != kItOmitted) { + mask |= ToItMask(i2, firstcond0, 2); + SetItCondition(i2, firstcond, 2); + if (i2 != kItOmitted) { + mask |= ToItMask(i3, firstcond0, 1); + SetItCondition(i3, firstcond, 3); + if (i3 != kItOmitted) { + mask |= 0b0001; + } + } + } + + // Start at first condition. + it_cond_index_ = 0; + next_condition_ = it_conditions_[0]; + uint16_t encoding = B15 | B13 | B12 | + B11 | B10 | B9 | B8 | + firstcond << 4 | + mask; + Emit16(encoding); +} + + +void Thumb2Assembler::cbz(Register rn, Label* label) { + CheckCondition(AL); + if (label->IsBound()) { + LOG(FATAL) << "cbz can only be used to branch forwards"; + } else { + uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false); + label->LinkTo(branchid); + } +} + + +void Thumb2Assembler::cbnz(Register rn, Label* label) { + CheckCondition(AL); + if (label->IsBound()) { + LOG(FATAL) << "cbnz can only be used to branch forwards"; + } else { + uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true); + label->LinkTo(branchid); + } +} + + +void Thumb2Assembler::blx(Register rm, Condition cond) { + CHECK_NE(rm, kNoRegister); + CheckCondition(cond); + int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3; + Emit16(encoding); +} + + +void Thumb2Assembler::bx(Register rm, Condition cond) { + CHECK_NE(rm, kNoRegister); + CheckCondition(cond); + int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3; + Emit16(encoding); +} + + +void Thumb2Assembler::Push(Register rd, Condition cond) { + str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond); +} + + +void Thumb2Assembler::Pop(Register rd, Condition cond) { + ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond); +} + + +void Thumb2Assembler::PushList(RegList regs, Condition cond) { + stm(DB_W, SP, regs, cond); +} + + +void Thumb2Assembler::PopList(RegList regs, Condition cond) { + ldm(IA_W, SP, regs, cond); +} + + +void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) { + if (cond != AL || rd != rm) { + mov(rd, ShifterOperand(rm), cond); + } +} + + +// A branch has changed size. Make a hole for it. +void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) { + // Move the contents of the buffer using: Move(newposition, oldposition) + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + buffer_.Move(location + delta, location); +} + + +void Thumb2Assembler::Bind(Label* label) { + CHECK(!label->IsBound()); + uint32_t bound_pc = buffer_.Size(); + std::vector<Branch*> changed_branches; + + while (label->IsLinked()) { + uint16_t position = label->Position(); // Branch id for linked branch. + Branch* branch = GetBranch(position); // Get the branch at this id. + bool changed = branch->Resolve(bound_pc); // Branch can be resolved now. + uint32_t branch_location = branch->GetLocation(); + uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain. + if (changed) { + MakeHoleForBranch(branch->GetLocation(), 2); + if (branch->IsCompareAndBranch()) { + // A cbz/cbnz instruction has changed size. There is no valid encoding for + // a 32 bit cbz/cbnz so we need to change this to an instruction pair: + // cmp rn, #0 + // b<eq|ne> target + bool n = branch->GetType() == Branch::kCompareAndBranchNonZero; + Condition cond = n ? NE : EQ; + branch->Move(2); // Move the branch forward by 2 bytes. + branch->ResetTypeAndCondition(Branch::kConditional, cond); + branch->ResetSize(Branch::k16Bit); + + // Now add a compare instruction in the place the branch was. + int16_t cmp = B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8; + buffer_.Store<int16_t>(branch_location, cmp); + + // Since have moved made a hole in the code we need to reload the + // current pc. + bound_pc = buffer_.Size(); + + // Now resolve the newly added branch. + changed = branch->Resolve(bound_pc); + if (changed) { + MakeHoleForBranch(branch->GetLocation(), 2); + changed_branches.push_back(branch); + } + } else { + changed_branches.push_back(branch); + } + } + label->position_ = next; // Move to next. + } + label->BindTo(bound_pc); + + // Now relocate any changed branches. Do this until there are no more changes. + std::vector<Branch*> branches_to_process = changed_branches; + while (branches_to_process.size() != 0) { + changed_branches.clear(); + for (auto& changed_branch : branches_to_process) { + for (auto& branch : branches_) { + bool changed = branch->Relocate(changed_branch->GetLocation(), 2); + if (changed) { + changed_branches.push_back(branch); + } + } + branches_to_process = changed_branches; + } + } +} + + +void Thumb2Assembler::EmitBranches() { + for (auto& branch : branches_) { + branch->Emit(&buffer_); + } +} + + +void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Do not use Lsl if no shift is wanted. + mov(rd, ShifterOperand(rm, LSL, shift_imm), cond); +} + + +void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted. + if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. + mov(rd, ShifterOperand(rm, LSR, shift_imm), cond); +} + + +void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted. + if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. + mov(rd, ShifterOperand(rm, ASR, shift_imm), cond); +} + + +void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm, + Condition cond) { + CHECK_NE(shift_imm, 0u); // Use Rrx instruction. + mov(rd, ShifterOperand(rm, ROR, shift_imm), cond); +} + + +void Thumb2Assembler::Rrx(Register rd, Register rm, Condition cond) { + mov(rd, ShifterOperand(rm, ROR, 0), cond); +} + + +int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) { + // The offset is off by 4 due to the way the ARM CPUs read PC. + offset -= 4; + offset >>= 1; + + uint32_t value = 0; + // There are two different encodings depending on the value of bit 12. In one case + // intermediate values are calculated using the sign bit. + if ((inst & B12) == B12) { + // 25 bits of offset. + uint32_t signbit = (offset >> 31) & 0x1; + uint32_t i1 = (offset >> 22) & 0x1; + uint32_t i2 = (offset >> 21) & 0x1; + uint32_t imm10 = (offset >> 11) & 0x03ff; + uint32_t imm11 = offset & 0x07ff; + uint32_t j1 = (i1 ^ signbit) ? 0 : 1; + uint32_t j2 = (i2 ^ signbit) ? 0 : 1; + value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | + imm11; + // Remove the offset from the current encoding. + inst &= ~(0x3ff << 16 | 0x7ff); + } else { + uint32_t signbit = (offset >> 31) & 0x1; + uint32_t imm6 = (offset >> 11) & 0x03f; + uint32_t imm11 = offset & 0x07ff; + uint32_t j1 = (offset >> 19) & 1; + uint32_t j2 = (offset >> 17) & 1; + value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) | + imm11; + // Remove the offset from the current encoding. + inst &= ~(0x3f << 16 | 0x7ff); + } + // Mask out offset bits in current instruction. + inst &= ~(B26 | B13 | B11); + inst |= value; + return inst; +} + + +int Thumb2Assembler::DecodeBranchOffset(int32_t instr) { + int32_t imm32; + if ((instr & B12) == B12) { + uint32_t S = (instr >> 26) & 1; + uint32_t J2 = (instr >> 11) & 1; + uint32_t J1 = (instr >> 13) & 1; + uint32_t imm10 = (instr >> 16) & 0x3FF; + uint32_t imm11 = instr & 0x7FF; + + uint32_t I1 = ~(J1 ^ S) & 1; + uint32_t I2 = ~(J2 ^ S) & 1; + imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); + imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate. + } else { + uint32_t S = (instr >> 26) & 1; + uint32_t J2 = (instr >> 11) & 1; + uint32_t J1 = (instr >> 13) & 1; + uint32_t imm6 = (instr >> 16) & 0x3F; + uint32_t imm11 = instr & 0x7FF; + + imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); + imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate. + } + imm32 += 4; + return imm32; +} + + +void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) { + AddConstant(rd, rd, value, cond); +} + + +void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value, + Condition cond) { + if (value == 0) { + if (rd != rn) { + mov(rd, ShifterOperand(rn), cond); + } + return; + } + // We prefer to select the shorter code sequence rather than selecting add for + // positive values and sub for negatives ones, which would slightly improve + // the readability of generated code for some constants. + ShifterOperand shifter_op; + if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) { + add(rd, rn, shifter_op, cond); + } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) { + sub(rd, rn, shifter_op, cond); + } else { + CHECK(rn != IP); + if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) { + mvn(IP, shifter_op, cond); + add(rd, rn, ShifterOperand(IP), cond); + } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) { + mvn(IP, shifter_op, cond); + sub(rd, rn, ShifterOperand(IP), cond); + } else { + movw(IP, Low16Bits(value), cond); + uint16_t value_high = High16Bits(value); + if (value_high != 0) { + movt(IP, value_high, cond); + } + add(rd, rn, ShifterOperand(IP), cond); + } + } +} + + +void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value, + Condition cond) { + ShifterOperand shifter_op; + if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) { + adds(rd, rn, shifter_op, cond); + } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) { + subs(rd, rn, shifter_op, cond); + } else { + CHECK(rn != IP); + if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) { + mvn(IP, shifter_op, cond); + adds(rd, rn, ShifterOperand(IP), cond); + } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) { + mvn(IP, shifter_op, cond); + subs(rd, rn, ShifterOperand(IP), cond); + } else { + movw(IP, Low16Bits(value), cond); + uint16_t value_high = High16Bits(value); + if (value_high != 0) { + movt(IP, value_high, cond); + } + adds(rd, rn, ShifterOperand(IP), cond); + } + } +} + + +void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { + ShifterOperand shifter_op; + if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) { + mov(rd, shifter_op, cond); + } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) { + mvn(rd, shifter_op, cond); + } else { + movw(rd, Low16Bits(value), cond); + uint16_t value_high = High16Bits(value); + if (value_high != 0) { + movt(rd, value_high, cond); + } + } +} + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldLoadOffsetThumb. +void Thumb2Assembler::LoadFromOffset(LoadOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldLoadOffsetThumb(type, offset)) { + CHECK(base != IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldLoadOffsetThumb(type, offset)); + switch (type) { + case kLoadSignedByte: + ldrsb(reg, Address(base, offset), cond); + break; + case kLoadUnsignedByte: + ldrb(reg, Address(base, offset), cond); + break; + case kLoadSignedHalfword: + ldrsh(reg, Address(base, offset), cond); + break; + case kLoadUnsignedHalfword: + ldrh(reg, Address(base, offset), cond); + break; + case kLoadWord: + ldr(reg, Address(base, offset), cond); + break; + case kLoadWordPair: + ldrd(reg, Address(base, offset), cond); + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset. +void Thumb2Assembler::LoadSFromOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)); + vldrs(reg, Address(base, offset), cond); +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset. +void Thumb2Assembler::LoadDFromOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)); + vldrd(reg, Address(base, offset), cond); +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldStoreOffsetThumb. +void Thumb2Assembler::StoreToOffset(StoreOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldStoreOffsetThumb(type, offset)) { + CHECK(reg != IP); + CHECK(base != IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldStoreOffsetThumb(type, offset)); + switch (type) { + case kStoreByte: + strb(reg, Address(base, offset), cond); + break; + case kStoreHalfword: + strh(reg, Address(base, offset), cond); + break; + case kStoreWord: + str(reg, Address(base, offset), cond); + break; + case kStoreWordPair: + strd(reg, Address(base, offset), cond); + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset. +void Thumb2Assembler::StoreSToOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)); + vstrs(reg, Address(base, offset), cond); +} + + +// Implementation note: this method must emit at most one instruction when +// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset. +void Thumb2Assembler::StoreDToOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond) { + if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) { + CHECK_NE(base, IP); + LoadImmediate(IP, offset, cond); + add(IP, IP, ShifterOperand(base), cond); + base = IP; + offset = 0; + } + CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)); + vstrd(reg, Address(base, offset), cond); +} + + +void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) { + CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12); +#if ANDROID_SMP != 0 + int32_t encoding = 0xf3bf8f5f; // dmb in T1 encoding. + Emit32(encoding); +#endif +} + + +void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) { + cbz(r, label); +} + + +void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) { + cbnz(r, label); +} +} // namespace arm +} // namespace art diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h new file mode 100644 index 0000000..60b9384 --- /dev/null +++ b/compiler/utils/arm/assembler_thumb2.h @@ -0,0 +1,685 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_ +#define ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_ + +#include <vector> + +#include "base/logging.h" +#include "constants_arm.h" +#include "utils/arm/managed_register_arm.h" +#include "utils/arm/assembler_arm.h" +#include "offsets.h" +#include "utils.h" + +namespace art { +namespace arm { + + +class Thumb2Assembler FINAL : public ArmAssembler { + public: + Thumb2Assembler() : force_32bit_(false), it_cond_index_(kNoItCondition), next_condition_(AL) { + } + + virtual ~Thumb2Assembler() { + for (auto& branch : branches_) { + delete branch; + } + } + + bool IsThumb() const OVERRIDE { + return true; + } + + bool IsForced32Bit() const { + return force_32bit_; + } + + void FinalizeInstructions(const MemoryRegion& region) OVERRIDE { + EmitBranches(); + Assembler::FinalizeInstructions(region); + } + + // Data-processing instructions. + void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void tst(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void teq(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void mov(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void movs(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + + // Miscellaneous data-processing instructions. + void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void movw(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; + void movt(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; + + // Multiply instructions. + void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + void mla(Register rd, Register rn, Register rm, Register ra, + Condition cond = AL) OVERRIDE; + void mls(Register rd, Register rn, Register rm, Register ra, + Condition cond = AL) OVERRIDE; + void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, + Condition cond = AL) OVERRIDE; + + void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + + // Load/store instructions. + void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void str(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void strb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void strh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrsb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void ldrsh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldrd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + void strd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; + + void ldm(BlockAddressMode am, Register base, + RegList regs, Condition cond = AL) OVERRIDE; + void stm(BlockAddressMode am, Register base, + RegList regs, Condition cond = AL) OVERRIDE; + + void ldrex(Register rd, Register rn, Condition cond = AL) OVERRIDE; + void strex(Register rd, Register rt, Register rn, Condition cond = AL) OVERRIDE; + + void ldrex(Register rd, Register rn, uint16_t imm, Condition cond = AL); + void strex(Register rd, Register rt, Register rn, uint16_t imm, Condition cond = AL); + + + // Miscellaneous instructions. + void clrex(Condition cond = AL) OVERRIDE; + void nop(Condition cond = AL) OVERRIDE; + + void bkpt(uint16_t imm16) OVERRIDE; + void svc(uint32_t imm24) OVERRIDE; + + // If-then + void it(Condition firstcond, ItState i1 = kItOmitted, + ItState i2 = kItOmitted, ItState i3 = kItOmitted) OVERRIDE; + + void cbz(Register rn, Label* target) OVERRIDE; + void cbnz(Register rn, Label* target) OVERRIDE; + + // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles). + void vmovsr(SRegister sn, Register rt, Condition cond = AL) OVERRIDE; + void vmovrs(Register rt, SRegister sn, Condition cond = AL) OVERRIDE; + void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) OVERRIDE; + void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) OVERRIDE; + void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) OVERRIDE; + void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) OVERRIDE; + void vmovs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vmovd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + + // Returns false if the immediate cannot be encoded. + bool vmovs(SRegister sd, float s_imm, Condition cond = AL) OVERRIDE; + bool vmovd(DRegister dd, double d_imm, Condition cond = AL) OVERRIDE; + + void vldrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE; + void vstrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE; + void vldrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE; + void vstrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE; + + void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE; + void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE; + + void vabss(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vabsd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + void vnegs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vnegd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + + void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE; + + void vcmps(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE; + void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE; + void vcmpsz(SRegister sd, Condition cond = AL) OVERRIDE; + void vcmpdz(DRegister dd, Condition cond = AL) OVERRIDE; + void vmstat(Condition cond = AL) OVERRIDE; // VMRS APSR_nzcv, FPSCR + + void vpushs(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; + void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE; + void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; + void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE; + + // Branch instructions. + void b(Label* label, Condition cond = AL); + void bl(Label* label, Condition cond = AL); + void blx(Label* label); + void blx(Register rm, Condition cond = AL) OVERRIDE; + void bx(Register rm, Condition cond = AL) OVERRIDE; + + void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); + void Rrx(Register rd, Register rm, Condition cond = AL); + + void Push(Register rd, Condition cond = AL) OVERRIDE; + void Pop(Register rd, Condition cond = AL) OVERRIDE; + + void PushList(RegList regs, Condition cond = AL) OVERRIDE; + void PopList(RegList regs, Condition cond = AL) OVERRIDE; + + void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE; + + void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE; + void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE; + + // Macros. + // Add signed constant value to rd. May clobber IP. + void AddConstant(Register rd, int32_t value, Condition cond = AL) OVERRIDE; + void AddConstant(Register rd, Register rn, int32_t value, + Condition cond = AL) OVERRIDE; + void AddConstantSetFlags(Register rd, Register rn, int32_t value, + Condition cond = AL) OVERRIDE; + void AddConstantWithCarry(Register rd, Register rn, int32_t value, + Condition cond = AL) {} + + // Load and Store. May clobber IP. + void LoadImmediate(Register rd, int32_t value, Condition cond = AL) OVERRIDE; + void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {} + void LoadDImmediate(DRegister dd, double value, + Register scratch, Condition cond = AL) {} + void MarkExceptionHandler(Label* label) OVERRIDE; + void LoadFromOffset(LoadOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void StoreToOffset(StoreOperandType type, + Register reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void LoadSFromOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void StoreSToOffset(SRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void LoadDFromOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + void StoreDToOffset(DRegister reg, + Register base, + int32_t offset, + Condition cond = AL) OVERRIDE; + + + static bool IsInstructionForExceptionHandling(uword pc); + + // Emit data (e.g. encoded instruction or immediate) to the. + // instruction stream. + void Emit32(int32_t value); // Emit a 32 bit instruction in thumb format. + void Emit16(int16_t value); // Emit a 16 bit instruction in little endian format. + void Bind(Label* label) OVERRIDE; + + void MemoryBarrier(ManagedRegister scratch) OVERRIDE; + + // Force the assembler to generate 32 bit instructions. + void Force32Bit() { + force_32bit_ = true; + } + + private: + // Emit a single 32 or 16 bit data processing instruction. + void EmitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so); + + // Must the instruction be 32 bits or can it possibly be encoded + // in 16 bits? + bool Is32BitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so); + + // Emit a 32 bit data processing instruction. + void Emit32BitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so); + + // Emit a 16 bit data processing instruction. + void Emit16BitDataProcessing(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so); + + void Emit16BitAddSub(Condition cond, + Opcode opcode, + int set_cc, + Register rn, + Register rd, + const ShifterOperand& so); + + uint16_t EmitCompareAndBranch(Register rn, uint16_t prev, bool n); + + void EmitLoadStore(Condition cond, + bool load, + bool byte, + bool half, + bool is_signed, + Register rd, + const Address& ad); + + void EmitMemOpAddressMode3(Condition cond, + int32_t mode, + Register rd, + const Address& ad); + + void EmitMultiMemOp(Condition cond, + BlockAddressMode am, + bool load, + Register base, + RegList regs); + + void EmitMulOp(Condition cond, + int32_t opcode, + Register rd, + Register rn, + Register rm, + Register rs); + + void EmitVFPsss(Condition cond, + int32_t opcode, + SRegister sd, + SRegister sn, + SRegister sm); + + void EmitVFPddd(Condition cond, + int32_t opcode, + DRegister dd, + DRegister dn, + DRegister dm); + + void EmitVFPsd(Condition cond, + int32_t opcode, + SRegister sd, + DRegister dm); + + void EmitVFPds(Condition cond, + int32_t opcode, + DRegister dd, + SRegister sm); + + void EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond); + + void EmitBranch(Condition cond, Label* label, bool link, bool x); + static int32_t EncodeBranchOffset(int32_t offset, int32_t inst); + static int DecodeBranchOffset(int32_t inst); + int32_t EncodeTstOffset(int offset, int32_t inst); + int DecodeTstOffset(int32_t inst); + + bool IsLowRegister(Register r) { + return r < R8; + } + + bool IsHighRegister(Register r) { + return r >= R8; + } + + bool force_32bit_; // Force the assembler to use 32 bit thumb2 instructions. + + // IfThen conditions. Used to check that conditional instructions match the preceding IT. + Condition it_conditions_[4]; + uint8_t it_cond_index_; + Condition next_condition_; + + void SetItCondition(ItState s, Condition cond, uint8_t index); + + void CheckCondition(Condition cond) { + CHECK_EQ(cond, next_condition_); + + // Move to the next condition if there is one. + if (it_cond_index_ < 3) { + ++it_cond_index_; + next_condition_ = it_conditions_[it_cond_index_]; + } else { + next_condition_ = AL; + } + } + + void CheckConditionLastIt(Condition cond) { + if (it_cond_index_ < 3) { + // Check that the next condition is AL. This means that the + // current condition is the last in the IT block. + CHECK_EQ(it_conditions_[it_cond_index_ + 1], AL); + } + CheckCondition(cond); + } + + // Branches. + // + // The thumb2 architecture allows branches to be either 16 or 32 bit instructions. This + // depends on both the type of branch and the offset to which it is branching. When + // generating code for branches we don't know the size before hand (if the branch is + // going forward, because we haven't seen the target address yet), so we need to assume + // that it is going to be one of 16 or 32 bits. When we know the target (the label is 'bound') + // we can determine the actual size of the branch. However, if we had guessed wrong before + // we knew the target there will be no room in the instruction sequence for the new + // instruction (assume that we never decrease the size of a branch). + // + // To handle this, we keep a record of every branch in the program. The actual instruction + // encoding for these is delayed until we know the final size of every branch. When we + // bind a label to a branch (we then know the target address) we determine if the branch + // has changed size. If it has we need to move all the instructions in the buffer after + // the branch point forward by the change in size of the branch. This will create a gap + // in the code big enough for the new branch encoding. However, since we have moved + // a chunk of code we need to relocate the branches in that code to their new address. + // + // Creating a hole in the code for the new branch encoding might cause another branch that was + // 16 bits to become 32 bits, so we need to find this in another pass. + // + // We also need to deal with a cbz/cbnz instruction that becomes too big for its offset + // range. We do this by converting it to two instructions: + // cmp Rn, #0 + // b<cond> target + // But we also need to handle the case where the conditional branch is out of range and + // becomes a 32 bit conditional branch. + // + // All branches have a 'branch id' which is a 16 bit unsigned number used to identify + // the branch. Unresolved labels use the branch id to link to the next unresolved branch. + + class Branch { + public: + // Branch type. + enum Type { + kUnconditional, // B. + kConditional, // B<cond>. + kCompareAndBranchZero, // cbz. + kCompareAndBranchNonZero, // cbnz. + kUnconditionalLink, // BL. + kUnconditionalLinkX, // BLX. + kUnconditionalX // BX. + }; + + // Calculated size of branch instruction based on type and offset. + enum Size { + k16Bit, + k32Bit + }; + + // Unresolved branch possibly with a condition. + Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, Condition cond = AL) : + assembler_(assembler), type_(type), location_(location), + target_(kUnresolved), + cond_(cond), rn_(R0) { + CHECK(!IsCompareAndBranch()); + size_ = CalculateSize(); + } + + // Unresolved compare-and-branch instruction with a register. + Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, Register rn) : + assembler_(assembler), type_(type), location_(location), + target_(kUnresolved), cond_(AL), rn_(rn) { + CHECK(IsCompareAndBranch()); + size_ = CalculateSize(); + } + + // Resolved branch (can't be compare-and-branch) with a target and possibly a condition. + Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, uint32_t target, + Condition cond = AL) : + assembler_(assembler), type_(type), location_(location), + target_(target), cond_(cond), rn_(R0) { + CHECK(!IsCompareAndBranch()); + // Resolved branch. + size_ = CalculateSize(); + } + + bool IsCompareAndBranch() const { + return type_ == kCompareAndBranchNonZero || type_ == kCompareAndBranchZero; + } + + // Resolve a branch when the target is known. If this causes the + // size of the branch to change return true. Otherwise return false. + bool Resolve(uint32_t target) { + target_ = target; + Size newsize = CalculateSize(); + if (size_ != newsize) { + size_ = newsize; + return true; + } + return false; + } + + // Move a cbz/cbnz branch. This is always forward. + void Move(int32_t delta) { + CHECK(IsCompareAndBranch()); + CHECK_GT(delta, 0); + location_ += delta; + target_ += delta; + } + + // Relocate a branch by a given delta. This changed the location and + // target if they need to be changed. It also recalculates the + // size of the branch instruction. It returns true if the branch + // has changed size. + bool Relocate(uint32_t oldlocation, int32_t delta) { + if (location_ > oldlocation) { + location_ += delta; + } + if (target_ != kUnresolved) { + if (target_ > oldlocation) { + target_ += delta; + } + } else { + return false; // Don't know the size yet. + } + + // Calculate the new size. + Size newsize = CalculateSize(); + if (size_ != newsize) { + size_ = newsize; + return true; + } + return false; + } + + Size GetSize() const { + return size_; + } + + Type GetType() const { + return type_; + } + + uint32_t GetLocation() const { + return location_; + } + + // Emit the branch instruction into the assembler buffer. This does the + // encoding into the thumb instruction. + void Emit(AssemblerBuffer* buffer) const; + + // Reset the type and condition to those given. This used for + // cbz/cbnz instructions when they are converted to cmp/b<cond> + void ResetTypeAndCondition(Type type, Condition cond) { + CHECK(IsCompareAndBranch()); + CHECK(cond == EQ || cond == NE); + type_ = type; + cond_ = cond; + } + + Register GetRegister() const { + return rn_; + } + + void ResetSize(Size size) { + size_ = size; + } + + private: + // Calculate the size of the branch instruction based on its type and offset. + Size CalculateSize() const { + if (target_ == kUnresolved) { + if (assembler_->IsForced32Bit() && (type_ == kUnconditional || type_ == kConditional)) { + return k32Bit; + } + return k16Bit; + } + int32_t delta = target_ - location_ - 4; + if (delta < 0) { + delta = -delta; + } + switch (type_) { + case kUnconditional: + if (assembler_->IsForced32Bit() || delta >= (1 << 11)) { + return k32Bit; + } else { + return k16Bit; + } + case kConditional: + if (assembler_->IsForced32Bit() || delta >= (1 << 8)) { + return k32Bit; + } else { + return k16Bit; + } + case kCompareAndBranchZero: + case kCompareAndBranchNonZero: + if (delta >= (1 << 7)) { + return k32Bit; // Will cause this branch to become invalid. + } + return k16Bit; + + case kUnconditionalX: + case kUnconditionalLinkX: + return k16Bit; + case kUnconditionalLink: + return k32Bit; + } + LOG(FATAL) << "Cannot reach"; + return k16Bit; + } + + static constexpr uint32_t kUnresolved = 0xffffffff; // Value for target_ for unresolved. + const Thumb2Assembler* assembler_; + Type type_; + uint32_t location_; // Offset into assembler buffer in bytes. + uint32_t target_; // Offset into assembler buffer in bytes. + Size size_; + Condition cond_; + const Register rn_; + }; + + std::vector<Branch*> branches_; + + // Add a resolved branch and return its size. + Branch::Size AddBranch(Branch::Type type, uint32_t location, uint32_t target, + Condition cond = AL) { + branches_.push_back(new Branch(this, type, location, target, cond)); + return branches_[branches_.size()-1]->GetSize(); + } + + // Add a compare and branch (with a register) and return its id. + uint16_t AddBranch(Branch::Type type, uint32_t location, Register rn) { + branches_.push_back(new Branch(this, type, location, rn)); + return branches_.size() - 1; + } + + // Add an unresolved branch and return its id. + uint16_t AddBranch(Branch::Type type, uint32_t location, Condition cond = AL) { + branches_.push_back(new Branch(this, type, location, cond)); + return branches_.size() - 1; + } + + Branch* GetBranch(uint16_t branchid) { + if (branchid >= branches_.size()) { + return nullptr; + } + return branches_[branchid]; + } + + void EmitBranches(); + void MakeHoleForBranch(uint32_t location, uint32_t size); +}; + +} // namespace arm +} // namespace art + +#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_ diff --git a/compiler/utils/arm/constants_arm.h b/compiler/utils/arm/constants_arm.h index 058f945..3e4cd43 100644 --- a/compiler/utils/arm/constants_arm.h +++ b/compiler/utils/arm/constants_arm.h @@ -155,7 +155,8 @@ enum Shift { LSR = 1, // Logical shift right ASR = 2, // Arithmetic shift right ROR = 3, // Rotate right - kMaxShift = 4 + RRX = 4, // Rotate right with extend. + kMaxShift }; @@ -210,7 +211,6 @@ enum InstructionFields { kBranchOffsetMask = 0x00ffffff }; - // Size (in bytes) of registers. const int kRegisterSize = 4; diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc index 26bdceb..68b784a 100644 --- a/compiler/utils/assembler.cc +++ b/compiler/utils/assembler.cc @@ -19,7 +19,8 @@ #include <algorithm> #include <vector> -#include "arm/assembler_arm.h" +#include "arm/assembler_arm32.h" +#include "arm/assembler_thumb2.h" #include "arm64/assembler_arm64.h" #include "mips/assembler_mips.h" #include "x86/assembler_x86.h" @@ -106,8 +107,9 @@ void AssemblerBuffer::ExtendCapacity() { Assembler* Assembler::Create(InstructionSet instruction_set) { switch (instruction_set) { case kArm: + return new arm::Arm32Assembler(); case kThumb2: - return new arm::ArmAssembler(); + return new arm::Thumb2Assembler(); case kArm64: return new arm64::Arm64Assembler(); case kMips: diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h index 19239e1..f72f5e5 100644 --- a/compiler/utils/assembler.h +++ b/compiler/utils/assembler.h @@ -38,6 +38,8 @@ class AssemblerFixup; namespace arm { class ArmAssembler; + class Arm32Assembler; + class Thumb2Assembler; } namespace arm64 { class Arm64Assembler; @@ -87,7 +89,7 @@ class Label { int LinkPosition() const { CHECK(IsLinked()); - return position_ - kWordSize; + return position_ - kPointerSize; } bool IsBound() const { return position_ < 0; } @@ -114,6 +116,8 @@ class Label { } friend class arm::ArmAssembler; + friend class arm::Arm32Assembler; + friend class arm::Thumb2Assembler; friend class mips::MipsAssembler; friend class x86::X86Assembler; friend class x86_64::X86_64Assembler; @@ -189,6 +193,15 @@ class AssemblerBuffer { *reinterpret_cast<T*>(contents_ + position) = value; } + void Move(size_t newposition, size_t oldposition) { + CHECK(HasEnsuredCapacity()); + // Move the contents of the buffer from oldposition to + // newposition by nbytes. + size_t nbytes = Size() - oldposition; + memmove(contents_ + newposition, contents_ + oldposition, nbytes); + cursor_ += newposition - oldposition; + } + // Emit a fixup at the current location. void EmitFixup(AssemblerFixup* fixup) { fixup->set_previous(fixup_); diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc new file mode 100644 index 0000000..b1eaba7 --- /dev/null +++ b/compiler/utils/assembler_thumb_test.cc @@ -0,0 +1,1225 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fstream> + +#include "gtest/gtest.h" +#include "utils/arm/assembler_thumb2.h" +#include "base/hex_dump.h" +#include "common_runtime_test.h" + +namespace art { +namespace arm { + +// Include results file (generated manually) +#include "assembler_thumb_test_expected.cc.inc" + +static constexpr bool kPrintResults = false; + +void SetAndroidData() { + const char* data = getenv("ANDROID_DATA"); + if (data == nullptr) { + setenv("ANDROID_DATA", "/tmp", 1); + } +} + +std::string GetAndroidToolsDir() { + std::string root; + const char* android_build_top = getenv("ANDROID_BUILD_TOP"); + if (android_build_top != nullptr) { + root += android_build_top; + } else { + // Not set by build server, so default to current directory + char* cwd = getcwd(nullptr, 0); + setenv("ANDROID_BUILD_TOP", cwd, 1); + root += cwd; + free(cwd); + } + + // Look for "prebuilts" + std::string toolsdir = root; + struct stat st; + while (toolsdir != "") { + std::string prebuilts = toolsdir + "/prebuilts"; + if (stat(prebuilts.c_str(), &st) == 0) { + // Found prebuilts. + toolsdir += "/prebuilts/gcc/linux-x86/arm"; + break; + } + // Not present, move up one dir. + size_t slash = toolsdir.rfind('/'); + if (slash == std::string::npos) { + toolsdir = ""; + } else { + toolsdir = toolsdir.substr(0, slash-1); + } + } + bool statok = stat(toolsdir.c_str(), &st) == 0; + if (!statok) { + LOG(FATAL) << "Cannot find ARM tools directory"; + } + + DIR* dir = opendir(toolsdir.c_str()); + if (dir == nullptr) { + LOG(FATAL) << "Unable to open ARM tools directory"; + } + + struct dirent* entry; + std::string founddir; + double maxversion = 0; + + // Find the latest version of the arm-eabi tools (biggest version number). + // Suffix on toolsdir will be something like "arm-eabi-4.8" + while ((entry = readdir(dir)) != nullptr) { + std::string subdir = toolsdir + std::string("/") + std::string(entry->d_name); + size_t eabi = subdir.find("arm-eabi-"); + if (eabi != std::string::npos) { + std::string suffix = subdir.substr(eabi + sizeof("arm-eabi-")); + double version = strtod(suffix.c_str(), nullptr); + if (version > maxversion) { + maxversion = version; + founddir = subdir; + } + } + } + closedir(dir); + bool found = founddir != ""; + if (!found) { + LOG(FATAL) << "Cannot find arm-eabi tools"; + } + + return founddir + "/bin"; +} + +void dump(std::vector<uint8_t>& code, const char* testname) { + // This will only work on the host. There is no as, objcopy or objdump on the + // device. +#ifndef HAVE_ANDROID_OS + static bool results_ok = false; + static std::string toolsdir; + + if (!results_ok) { + setup_results(); + toolsdir = GetAndroidToolsDir(); + SetAndroidData(); + results_ok = true; + } + + ScratchFile file; + + const char* filename = file.GetFilename().c_str(); + + std::ofstream out(filename); + if (out) { + out << ".section \".text\"\n"; + out << ".syntax unified\n"; + out << ".arch armv7-a\n"; + out << ".thumb\n"; + out << ".thumb_func\n"; + out << ".type " << testname << ", #function\n"; + out << ".global " << testname << "\n"; + out << testname << ":\n"; + out << ".fnstart\n"; + + for (uint32_t i = 0 ; i < code.size(); ++i) { + out << ".byte " << (static_cast<int>(code[i]) & 0xff) << "\n"; + } + out << ".fnend\n"; + out << ".size " << testname << ", .-" << testname << "\n"; + } + out.close(); + + char cmd[256]; + + // Assemble the .S + snprintf(cmd, sizeof(cmd), "%s/arm-eabi-as %s -o %s.o", toolsdir.c_str(), filename, filename); + system(cmd); + + // Remove the $d symbols to prevent the disassembler dumping the instructions + // as .word + snprintf(cmd, sizeof(cmd), "%s/arm-eabi-objcopy -N '$d' %s.o %s.oo", toolsdir.c_str(), + filename, filename); + system(cmd); + + // Disassemble. + + snprintf(cmd, sizeof(cmd), "%s/arm-eabi-objdump -d %s.oo | grep '^ *[0-9a-f][0-9a-f]*:'", + toolsdir.c_str(), filename); + if (kPrintResults) { + // Print the results only, don't check. This is used to generate new output for inserting + // into the .inc file. + system(cmd); + } else { + // Check the results match the appropriate results in the .inc file. + FILE *fp = popen(cmd, "r"); + ASSERT_TRUE(fp != nullptr); + + std::map<std::string, const char**>::iterator results = test_results.find(testname); + ASSERT_NE(results, test_results.end()); + + uint32_t lineindex = 0; + + while (!feof(fp)) { + char testline[256]; + char *s = fgets(testline, sizeof(testline), fp); + if (s == nullptr) { + break; + } + ASSERT_EQ(strcmp(results->second[lineindex], testline), 0); + ++lineindex; + } + // Check that we are at the end. + ASSERT_TRUE(results->second[lineindex] == nullptr); + fclose(fp); + } + + char buf[FILENAME_MAX]; + snprintf(buf, sizeof(buf), "%s.o", filename); + unlink(buf); + + snprintf(buf, sizeof(buf), "%s.oo", filename); + unlink(buf); +#endif +} + +#define __ assembler-> + +TEST(Thumb2AssemblerTest, SimpleMov) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mov(R0, ShifterOperand(R1)); + __ mov(R8, ShifterOperand(R9)); + + __ mov(R0, ShifterOperand(1)); + __ mov(R8, ShifterOperand(9)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "SimpleMov"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, SimpleMov32) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + assembler->Force32Bit(); + + __ mov(R0, ShifterOperand(R1)); + __ mov(R8, ShifterOperand(R9)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "SimpleMov32"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, SimpleMovAdd) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mov(R0, ShifterOperand(R1)); + __ add(R0, R1, ShifterOperand(R2)); + __ add(R0, R1, ShifterOperand()); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "SimpleMovAdd"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, DataProcessingRegister) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mov(R0, ShifterOperand(R1)); + __ mvn(R0, ShifterOperand(R1)); + + // 32 bit variants. + __ add(R0, R1, ShifterOperand(R2)); + __ sub(R0, R1, ShifterOperand(R2)); + __ and_(R0, R1, ShifterOperand(R2)); + __ orr(R0, R1, ShifterOperand(R2)); + __ eor(R0, R1, ShifterOperand(R2)); + __ bic(R0, R1, ShifterOperand(R2)); + __ adc(R0, R1, ShifterOperand(R2)); + __ sbc(R0, R1, ShifterOperand(R2)); + __ rsb(R0, R1, ShifterOperand(R2)); + + // 16 bit variants. + __ add(R0, R1, ShifterOperand()); + __ sub(R0, R1, ShifterOperand()); + __ and_(R0, R1, ShifterOperand()); + __ orr(R0, R1, ShifterOperand()); + __ eor(R0, R1, ShifterOperand()); + __ bic(R0, R1, ShifterOperand()); + __ adc(R0, R1, ShifterOperand()); + __ sbc(R0, R1, ShifterOperand()); + __ rsb(R0, R1, ShifterOperand()); + + __ tst(R0, ShifterOperand(R1)); + __ teq(R0, ShifterOperand(R1)); + __ cmp(R0, ShifterOperand(R1)); + __ cmn(R0, ShifterOperand(R1)); + + __ movs(R0, ShifterOperand(R1)); + __ mvns(R0, ShifterOperand(R1)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "DataProcessingRegister"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, DataProcessingImmediate) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mov(R0, ShifterOperand(0x55)); + __ mvn(R0, ShifterOperand(0x55)); + __ add(R0, R1, ShifterOperand(0x55)); + __ sub(R0, R1, ShifterOperand(0x55)); + __ and_(R0, R1, ShifterOperand(0x55)); + __ orr(R0, R1, ShifterOperand(0x55)); + __ eor(R0, R1, ShifterOperand(0x55)); + __ bic(R0, R1, ShifterOperand(0x55)); + __ adc(R0, R1, ShifterOperand(0x55)); + __ sbc(R0, R1, ShifterOperand(0x55)); + __ rsb(R0, R1, ShifterOperand(0x55)); + + __ tst(R0, ShifterOperand(0x55)); + __ teq(R0, ShifterOperand(0x55)); + __ cmp(R0, ShifterOperand(0x55)); + __ cmn(R0, ShifterOperand(0x55)); + + __ add(R0, R1, ShifterOperand(5)); + __ sub(R0, R1, ShifterOperand(5)); + + __ movs(R0, ShifterOperand(0x55)); + __ mvns(R0, ShifterOperand(0x55)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "DataProcessingImmediate"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediate) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mov(R0, ShifterOperand(0x550055)); + __ mvn(R0, ShifterOperand(0x550055)); + __ add(R0, R1, ShifterOperand(0x550055)); + __ sub(R0, R1, ShifterOperand(0x550055)); + __ and_(R0, R1, ShifterOperand(0x550055)); + __ orr(R0, R1, ShifterOperand(0x550055)); + __ eor(R0, R1, ShifterOperand(0x550055)); + __ bic(R0, R1, ShifterOperand(0x550055)); + __ adc(R0, R1, ShifterOperand(0x550055)); + __ sbc(R0, R1, ShifterOperand(0x550055)); + __ rsb(R0, R1, ShifterOperand(0x550055)); + + __ tst(R0, ShifterOperand(0x550055)); + __ teq(R0, ShifterOperand(0x550055)); + __ cmp(R0, ShifterOperand(0x550055)); + __ cmn(R0, ShifterOperand(0x550055)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "DataProcessingModifiedImmediate"); + delete assembler; +} + + +TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediates) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mov(R0, ShifterOperand(0x550055)); + __ mov(R0, ShifterOperand(0x55005500)); + __ mov(R0, ShifterOperand(0x55555555)); + __ mov(R0, ShifterOperand(0xd5000000)); // rotated to first position + __ mov(R0, ShifterOperand(0x6a000000)); // rotated to second position + __ mov(R0, ShifterOperand(0x350)); // rotated to 2nd last position + __ mov(R0, ShifterOperand(0x1a8)); // rotated to last position + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "DataProcessingModifiedImmediates"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, DataProcessingShiftedRegister) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mov(R3, ShifterOperand(R4, LSL, 4)); + __ mov(R3, ShifterOperand(R4, LSR, 5)); + __ mov(R3, ShifterOperand(R4, ASR, 6)); + __ mov(R3, ShifterOperand(R4, ROR, 7)); + __ mov(R3, ShifterOperand(R4, ROR)); + + // 32 bit variants. + __ mov(R8, ShifterOperand(R4, LSL, 4)); + __ mov(R8, ShifterOperand(R4, LSR, 5)); + __ mov(R8, ShifterOperand(R4, ASR, 6)); + __ mov(R8, ShifterOperand(R4, ROR, 7)); + __ mov(R8, ShifterOperand(R4, RRX)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "DataProcessingShiftedRegister"); + delete assembler; +} + + +TEST(Thumb2AssemblerTest, BasicLoad) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ ldr(R3, Address(R4, 24)); + __ ldrb(R3, Address(R4, 24)); + __ ldrh(R3, Address(R4, 24)); + __ ldrsb(R3, Address(R4, 24)); + __ ldrsh(R3, Address(R4, 24)); + + __ ldr(R3, Address(SP, 24)); + + // 32 bit variants + __ ldr(R8, Address(R4, 24)); + __ ldrb(R8, Address(R4, 24)); + __ ldrh(R8, Address(R4, 24)); + __ ldrsb(R8, Address(R4, 24)); + __ ldrsh(R8, Address(R4, 24)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "BasicLoad"); + delete assembler; +} + + +TEST(Thumb2AssemblerTest, BasicStore) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ str(R3, Address(R4, 24)); + __ strb(R3, Address(R4, 24)); + __ strh(R3, Address(R4, 24)); + + __ str(R3, Address(SP, 24)); + + // 32 bit variants. + __ str(R8, Address(R4, 24)); + __ strb(R8, Address(R4, 24)); + __ strh(R8, Address(R4, 24)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "BasicStore"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, ComplexLoad) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ ldr(R3, Address(R4, 24, Address::Mode::Offset)); + __ ldr(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ ldr(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ ldr(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ ldr(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ ldr(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + __ ldrb(R3, Address(R4, 24, Address::Mode::Offset)); + __ ldrb(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ ldrb(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ ldrb(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ ldrb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ ldrb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + __ ldrh(R3, Address(R4, 24, Address::Mode::Offset)); + __ ldrh(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ ldrh(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ ldrh(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ ldrh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ ldrh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + __ ldrsb(R3, Address(R4, 24, Address::Mode::Offset)); + __ ldrsb(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ ldrsb(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ ldrsb(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ ldrsb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ ldrsb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + __ ldrsh(R3, Address(R4, 24, Address::Mode::Offset)); + __ ldrsh(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ ldrsh(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ ldrsh(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "ComplexLoad"); + delete assembler; +} + + +TEST(Thumb2AssemblerTest, ComplexStore) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ str(R3, Address(R4, 24, Address::Mode::Offset)); + __ str(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ str(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ str(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ str(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ str(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + __ strb(R3, Address(R4, 24, Address::Mode::Offset)); + __ strb(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ strb(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ strb(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ strb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ strb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + __ strh(R3, Address(R4, 24, Address::Mode::Offset)); + __ strh(R3, Address(R4, 24, Address::Mode::PreIndex)); + __ strh(R3, Address(R4, 24, Address::Mode::PostIndex)); + __ strh(R3, Address(R4, 24, Address::Mode::NegOffset)); + __ strh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); + __ strh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "ComplexStore"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, NegativeLoadStore) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ ldr(R3, Address(R4, -24, Address::Mode::Offset)); + __ ldr(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ ldr(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ ldr(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ ldr(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ ldr(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + __ ldrb(R3, Address(R4, -24, Address::Mode::Offset)); + __ ldrb(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ ldrb(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ ldrb(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ ldrb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ ldrb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + __ ldrh(R3, Address(R4, -24, Address::Mode::Offset)); + __ ldrh(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ ldrh(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ ldrh(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ ldrh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ ldrh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + __ ldrsb(R3, Address(R4, -24, Address::Mode::Offset)); + __ ldrsb(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ ldrsb(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ ldrsb(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ ldrsb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ ldrsb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + __ ldrsh(R3, Address(R4, -24, Address::Mode::Offset)); + __ ldrsh(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ ldrsh(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ ldrsh(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ ldrsh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ ldrsh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + __ str(R3, Address(R4, -24, Address::Mode::Offset)); + __ str(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ str(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ str(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ str(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ str(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + __ strb(R3, Address(R4, -24, Address::Mode::Offset)); + __ strb(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ strb(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ strb(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ strb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ strb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + __ strh(R3, Address(R4, -24, Address::Mode::Offset)); + __ strh(R3, Address(R4, -24, Address::Mode::PreIndex)); + __ strh(R3, Address(R4, -24, Address::Mode::PostIndex)); + __ strh(R3, Address(R4, -24, Address::Mode::NegOffset)); + __ strh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); + __ strh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "NegativeLoadStore"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, SimpleLoadStoreDual) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ strd(R2, Address(R0, 24, Address::Mode::Offset)); + __ ldrd(R2, Address(R0, 24, Address::Mode::Offset)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "SimpleLoadStoreDual"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, ComplexLoadStoreDual) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ strd(R2, Address(R0, 24, Address::Mode::Offset)); + __ strd(R2, Address(R0, 24, Address::Mode::PreIndex)); + __ strd(R2, Address(R0, 24, Address::Mode::PostIndex)); + __ strd(R2, Address(R0, 24, Address::Mode::NegOffset)); + __ strd(R2, Address(R0, 24, Address::Mode::NegPreIndex)); + __ strd(R2, Address(R0, 24, Address::Mode::NegPostIndex)); + + __ ldrd(R2, Address(R0, 24, Address::Mode::Offset)); + __ ldrd(R2, Address(R0, 24, Address::Mode::PreIndex)); + __ ldrd(R2, Address(R0, 24, Address::Mode::PostIndex)); + __ ldrd(R2, Address(R0, 24, Address::Mode::NegOffset)); + __ ldrd(R2, Address(R0, 24, Address::Mode::NegPreIndex)); + __ ldrd(R2, Address(R0, 24, Address::Mode::NegPostIndex)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "ComplexLoadStoreDual"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, NegativeLoadStoreDual) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ strd(R2, Address(R0, -24, Address::Mode::Offset)); + __ strd(R2, Address(R0, -24, Address::Mode::PreIndex)); + __ strd(R2, Address(R0, -24, Address::Mode::PostIndex)); + __ strd(R2, Address(R0, -24, Address::Mode::NegOffset)); + __ strd(R2, Address(R0, -24, Address::Mode::NegPreIndex)); + __ strd(R2, Address(R0, -24, Address::Mode::NegPostIndex)); + + __ ldrd(R2, Address(R0, -24, Address::Mode::Offset)); + __ ldrd(R2, Address(R0, -24, Address::Mode::PreIndex)); + __ ldrd(R2, Address(R0, -24, Address::Mode::PostIndex)); + __ ldrd(R2, Address(R0, -24, Address::Mode::NegOffset)); + __ ldrd(R2, Address(R0, -24, Address::Mode::NegPreIndex)); + __ ldrd(R2, Address(R0, -24, Address::Mode::NegPostIndex)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "NegativeLoadStoreDual"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, SimpleBranch) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + __ mov(R0, ShifterOperand(2)); + __ Bind(&l1); + __ mov(R1, ShifterOperand(1)); + __ b(&l1); + Label l2; + __ b(&l2); + __ mov(R1, ShifterOperand(2)); + __ Bind(&l2); + __ mov(R0, ShifterOperand(3)); + + Label l3; + __ mov(R0, ShifterOperand(2)); + __ Bind(&l3); + __ mov(R1, ShifterOperand(1)); + __ b(&l3, EQ); + + Label l4; + __ b(&l4, EQ); + __ mov(R1, ShifterOperand(2)); + __ Bind(&l4); + __ mov(R0, ShifterOperand(3)); + + // 2 linked labels. + Label l5; + __ b(&l5); + __ mov(R1, ShifterOperand(4)); + __ b(&l5); + __ mov(R1, ShifterOperand(5)); + __ Bind(&l5); + __ mov(R0, ShifterOperand(6)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "SimpleBranch"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, LongBranch) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + assembler->Force32Bit(); + // 32 bit branches. + Label l1; + __ mov(R0, ShifterOperand(2)); + __ Bind(&l1); + __ mov(R1, ShifterOperand(1)); + __ b(&l1); + + Label l2; + __ b(&l2); + __ mov(R1, ShifterOperand(2)); + __ Bind(&l2); + __ mov(R0, ShifterOperand(3)); + + Label l3; + __ mov(R0, ShifterOperand(2)); + __ Bind(&l3); + __ mov(R1, ShifterOperand(1)); + __ b(&l3, EQ); + + Label l4; + __ b(&l4, EQ); + __ mov(R1, ShifterOperand(2)); + __ Bind(&l4); + __ mov(R0, ShifterOperand(3)); + + // 2 linked labels. + Label l5; + __ b(&l5); + __ mov(R1, ShifterOperand(4)); + __ b(&l5); + __ mov(R1, ShifterOperand(5)); + __ Bind(&l5); + __ mov(R0, ShifterOperand(6)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "LongBranch"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, LoadMultiple) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + // 16 bit. + __ ldm(DB_W, R4, (1 << R0 | 1 << R3)); + + // 32 bit. + __ ldm(DB_W, R4, (1 << LR | 1 << R11)); + __ ldm(DB, R4, (1 << LR | 1 << R11)); + + // Single reg is converted to ldr + __ ldm(DB_W, R4, (1 << R5)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "LoadMultiple"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, StoreMultiple) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + // 16 bit. + __ stm(IA_W, R4, (1 << R0 | 1 << R3)); + + // 32 bit. + __ stm(IA_W, R4, (1 << LR | 1 << R11)); + __ stm(IA, R4, (1 << LR | 1 << R11)); + + // Single reg is converted to str + __ stm(IA_W, R4, (1 << R5)); + __ stm(IA, R4, (1 << R5)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "StoreMultiple"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, MovWMovT) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ movw(R4, 0); // 16 bit. + __ movw(R4, 0x34); // 16 bit. + __ movw(R9, 0x34); // 32 bit due to high register. + __ movw(R3, 0x1234); // 32 bit due to large value. + __ movw(R9, 0xffff); // 32 bit due to large value and high register. + + // Always 32 bit. + __ movt(R0, 0); + __ movt(R0, 0x1234); + __ movt(R1, 0xffff); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "MovWMovT"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, SpecialAddSub) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ add(R2, SP, ShifterOperand(0x50)); // 16 bit. + __ add(SP, SP, ShifterOperand(0x50)); // 16 bit. + __ add(R8, SP, ShifterOperand(0x50)); // 32 bit. + + __ add(R2, SP, ShifterOperand(0xf00)); // 32 bit due to imm size. + __ add(SP, SP, ShifterOperand(0xf00)); // 32 bit due to imm size. + + __ sub(SP, SP, ShifterOperand(0x50)); // 16 bit + __ sub(R0, SP, ShifterOperand(0x50)); // 32 bit + __ sub(R8, SP, ShifterOperand(0x50)); // 32 bit. + + __ sub(SP, SP, ShifterOperand(0xf00)); // 32 bit due to imm size + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "SpecialAddSub"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, StoreToOffset) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ StoreToOffset(kStoreWord, R2, R4, 12); // Simple + __ StoreToOffset(kStoreWord, R2, R4, 0x2000); // Offset too big. + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "StoreToOffset"); + delete assembler; +} + + +TEST(Thumb2AssemblerTest, IfThen) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ it(EQ); + __ mov(R1, ShifterOperand(1), EQ); + + __ it(EQ, kItThen); + __ mov(R1, ShifterOperand(1), EQ); + __ mov(R2, ShifterOperand(2), EQ); + + __ it(EQ, kItElse); + __ mov(R1, ShifterOperand(1), EQ); + __ mov(R2, ShifterOperand(2), NE); + + __ it(EQ, kItThen, kItElse); + __ mov(R1, ShifterOperand(1), EQ); + __ mov(R2, ShifterOperand(2), EQ); + __ mov(R3, ShifterOperand(3), NE); + + __ it(EQ, kItElse, kItElse); + __ mov(R1, ShifterOperand(1), EQ); + __ mov(R2, ShifterOperand(2), NE); + __ mov(R3, ShifterOperand(3), NE); + + __ it(EQ, kItThen, kItThen, kItElse); + __ mov(R1, ShifterOperand(1), EQ); + __ mov(R2, ShifterOperand(2), EQ); + __ mov(R3, ShifterOperand(3), EQ); + __ mov(R4, ShifterOperand(4), NE); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "IfThen"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, CbzCbnz) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + __ cbz(R2, &l1); + __ mov(R1, ShifterOperand(3)); + __ mov(R2, ShifterOperand(3)); + __ Bind(&l1); + __ mov(R2, ShifterOperand(4)); + + Label l2; + __ cbnz(R2, &l2); + __ mov(R8, ShifterOperand(3)); + __ mov(R2, ShifterOperand(3)); + __ Bind(&l2); + __ mov(R2, ShifterOperand(4)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "CbzCbnz"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, Multiply) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ mul(R0, R1, R0); + __ mul(R0, R1, R2); + __ mul(R8, R9, R8); + __ mul(R8, R9, R10); + + __ mla(R0, R1, R2, R3); + __ mla(R8, R9, R8, R9); + + __ mls(R0, R1, R2, R3); + __ mls(R8, R9, R8, R9); + + __ umull(R0, R1, R2, R3); + __ umull(R8, R9, R10, R11); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "Multiply"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, Divide) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ sdiv(R0, R1, R2); + __ sdiv(R8, R9, R10); + + __ udiv(R0, R1, R2); + __ udiv(R8, R9, R10); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "Divide"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, VMov) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ vmovs(S1, 1.0); + __ vmovd(D1, 1.0); + + __ vmovs(S1, S2); + __ vmovd(D1, D2); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "VMov"); + delete assembler; +} + + +TEST(Thumb2AssemblerTest, BasicFloatingPoint) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ vadds(S0, S1, S2); + __ vsubs(S0, S1, S2); + __ vmuls(S0, S1, S2); + __ vmlas(S0, S1, S2); + __ vmlss(S0, S1, S2); + __ vdivs(S0, S1, S2); + __ vabss(S0, S1); + __ vnegs(S0, S1); + __ vsqrts(S0, S1); + + __ vaddd(D0, D1, D2); + __ vsubd(D0, D1, D2); + __ vmuld(D0, D1, D2); + __ vmlad(D0, D1, D2); + __ vmlsd(D0, D1, D2); + __ vdivd(D0, D1, D2); + __ vabsd(D0, D1); + __ vnegd(D0, D1); + __ vsqrtd(D0, D1); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "BasicFloatingPoint"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, FloatingPointConversions) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ vcvtsd(S2, D2); + __ vcvtds(D2, S2); + + __ vcvtis(S1, S2); + __ vcvtsi(S1, S2); + + __ vcvtid(S1, D2); + __ vcvtdi(D1, S2); + + __ vcvtus(S1, S2); + __ vcvtsu(S1, S2); + + __ vcvtud(S1, D2); + __ vcvtdu(D1, S2); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "FloatingPointConversions"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, FloatingPointComparisons) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ vcmps(S0, S1); + __ vcmpd(D0, D1); + + __ vcmpsz(S2); + __ vcmpdz(D2); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "FloatingPointComparisons"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, Calls) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ blx(LR); + __ bx(LR); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "Calls"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, Breakpoint) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ bkpt(0); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "Breakpoint"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, StrR1) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ str(R1, Address(SP, 68)); + __ str(R1, Address(SP, 1068)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "StrR1"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, VPushPop) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + __ vpushs(S2, 4); + __ vpushd(D2, 4); + + __ vpops(S2, 4); + __ vpopd(D2, 4); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "VPushPop"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, Max16BitBranch) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + __ b(&l1); + for (int i = 0 ; i < (1 << 11) ; i += 2) { + __ mov(R3, ShifterOperand(i & 0xff)); + } + __ Bind(&l1); + __ mov(R1, ShifterOperand(R2)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "Max16BitBranch"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, Branch32) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + __ b(&l1); + for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { + __ mov(R3, ShifterOperand(i & 0xff)); + } + __ Bind(&l1); + __ mov(R1, ShifterOperand(R2)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "Branch32"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, CompareAndBranchMax) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + __ cbz(R4, &l1); + for (int i = 0 ; i < (1 << 7) ; i += 2) { + __ mov(R3, ShifterOperand(i & 0xff)); + } + __ Bind(&l1); + __ mov(R1, ShifterOperand(R2)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "CompareAndBranchMax"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, CompareAndBranchRelocation16) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + __ cbz(R4, &l1); + for (int i = 0 ; i < (1 << 7) + 2 ; i += 2) { + __ mov(R3, ShifterOperand(i & 0xff)); + } + __ Bind(&l1); + __ mov(R1, ShifterOperand(R2)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "CompareAndBranchRelocation16"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, CompareAndBranchRelocation32) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + __ cbz(R4, &l1); + for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { + __ mov(R3, ShifterOperand(i & 0xff)); + } + __ Bind(&l1); + __ mov(R1, ShifterOperand(R2)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "CompareAndBranchRelocation32"); + delete assembler; +} + +TEST(Thumb2AssemblerTest, MixedBranch32) { + arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); + + Label l1; + Label l2; + __ b(&l1); // Forwards. + __ Bind(&l2); + + // Space to force relocation. + for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { + __ mov(R3, ShifterOperand(i & 0xff)); + } + __ b(&l2); // Backwards. + __ Bind(&l1); + __ mov(R1, ShifterOperand(R2)); + + size_t cs = __ CodeSize(); + std::vector<uint8_t> managed_code(cs); + MemoryRegion code(&managed_code[0], managed_code.size()); + __ FinalizeInstructions(code); + dump(managed_code, "MixedBranch32"); + delete assembler; +} + +#undef __ +} // namespace arm +} // namespace art diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc new file mode 100644 index 0000000..c5f2226 --- /dev/null +++ b/compiler/utils/assembler_thumb_test_expected.cc.inc @@ -0,0 +1,4788 @@ +const char* SimpleMovResults[] = { + " 0: 0008 movs r0, r1\n", + " 2: 46c8 mov r8, r9\n", + " 4: 2001 movs r0, #1\n", + " 6: f04f 0809 mov.w r8, #9\n", + nullptr +}; +const char* SimpleMov32Results[] = { + " 0: ea4f 0001 mov.w r0, r1\n", + " 4: ea4f 0809 mov.w r8, r9\n", + nullptr +}; +const char* SimpleMovAddResults[] = { + " 0: 0008 movs r0, r1\n", + " 2: 1888 adds r0, r1, r2\n", + " 4: 1c08 adds r0, r1, #0\n", + nullptr +}; +const char* DataProcessingRegisterResults[] = { + " 0: 0008 movs r0, r1\n", + " 2: 43c8 mvns r0, r1\n", + " 4: 1888 adds r0, r1, r2\n", + " 6: 1a88 subs r0, r1, r2\n", + " 8: ea01 0002 and.w r0, r1, r2\n", + " c: ea41 0002 orr.w r0, r1, r2\n", + " 10: ea81 0002 eor.w r0, r1, r2\n", + " 14: ea21 0002 bic.w r0, r1, r2\n", + " 18: eb41 0002 adc.w r0, r1, r2\n", + " 1c: eb61 0002 sbc.w r0, r1, r2\n", + " 20: ebc1 0002 rsb r0, r1, r2\n", + " 24: 1c08 adds r0, r1, #0\n", + " 26: 1e08 subs r0, r1, #0\n", + " 28: 4008 ands r0, r1\n", + " 2a: 4308 orrs r0, r1\n", + " 2c: 4048 eors r0, r1\n", + " 2e: 4388 bics r0, r1\n", + " 30: 4148 adcs r0, r1\n", + " 32: 4188 sbcs r0, r1\n", + " 34: 4248 negs r0, r1\n", + " 36: 4208 tst r0, r1\n", + " 38: ea90 0f01 teq r0, r1\n", + " 3c: 4288 cmp r0, r1\n", + " 3e: 42c8 cmn r0, r1\n", + " 40: 0008 movs r0, r1\n", + " 42: 43c8 mvns r0, r1\n", + nullptr +}; +const char* DataProcessingImmediateResults[] = { + " 0: 2055 movs r0, #85 ; 0x55\n", + " 2: f06f 0055 mvn.w r0, #85 ; 0x55\n", + " 6: f101 0055 add.w r0, r1, #85 ; 0x55\n", + " a: f1a1 0055 sub.w r0, r1, #85 ; 0x55\n", + " e: f001 0055 and.w r0, r1, #85 ; 0x55\n", + " 12: f041 0055 orr.w r0, r1, #85 ; 0x55\n", + " 16: f081 0055 eor.w r0, r1, #85 ; 0x55\n", + " 1a: f021 0055 bic.w r0, r1, #85 ; 0x55\n", + " 1e: f141 0055 adc.w r0, r1, #85 ; 0x55\n", + " 22: f161 0055 sbc.w r0, r1, #85 ; 0x55\n", + " 26: f1c1 0055 rsb r0, r1, #85 ; 0x55\n", + " 2a: f010 0f55 tst.w r0, #85 ; 0x55\n", + " 2e: f090 0f55 teq r0, #85 ; 0x55\n", + " 32: 2855 cmp r0, #85 ; 0x55\n", + " 34: f110 0f55 cmn.w r0, #85 ; 0x55\n", + " 38: 1d48 adds r0, r1, #5\n", + " 3a: 1f48 subs r0, r1, #5\n", + " 3c: 2055 movs r0, #85 ; 0x55\n", + " 3e: f07f 0055 mvns.w r0, #85 ; 0x55\n", + nullptr +}; +const char* DataProcessingModifiedImmediateResults[] = { + " 0: f04f 1055 mov.w r0, #5570645 ; 0x550055\n", + " 4: f06f 1055 mvn.w r0, #5570645 ; 0x550055\n", + " 8: f101 1055 add.w r0, r1, #5570645 ; 0x550055\n", + " c: f1a1 1055 sub.w r0, r1, #5570645 ; 0x550055\n", + " 10: f001 1055 and.w r0, r1, #5570645 ; 0x550055\n", + " 14: f041 1055 orr.w r0, r1, #5570645 ; 0x550055\n", + " 18: f081 1055 eor.w r0, r1, #5570645 ; 0x550055\n", + " 1c: f021 1055 bic.w r0, r1, #5570645 ; 0x550055\n", + " 20: f141 1055 adc.w r0, r1, #5570645 ; 0x550055\n", + " 24: f161 1055 sbc.w r0, r1, #5570645 ; 0x550055\n", + " 28: f1c1 1055 rsb r0, r1, #5570645 ; 0x550055\n", + " 2c: f010 1f55 tst.w r0, #5570645 ; 0x550055\n", + " 30: f090 1f55 teq r0, #5570645 ; 0x550055\n", + " 34: f1b0 1f55 cmp.w r0, #5570645 ; 0x550055\n", + " 38: f110 1f55 cmn.w r0, #5570645 ; 0x550055\n", + nullptr +}; +const char* DataProcessingModifiedImmediatesResults[] = { + " 0: f04f 1055 mov.w r0, #5570645 ; 0x550055\n", + " 4: f04f 2055 mov.w r0, #1426085120 ; 0x55005500\n", + " 8: f04f 3055 mov.w r0, #1431655765 ; 0x55555555\n", + " c: f04f 4055 mov.w r0, #3573547008 ; 0xd5000000\n", + " 10: f04f 40d4 mov.w r0, #1778384896 ; 0x6a000000\n", + " 14: f44f 7054 mov.w r0, #848 ; 0x350\n", + " 18: f44f 70d4 mov.w r0, #424 ; 0x1a8\n", + nullptr +}; +const char* DataProcessingShiftedRegisterResults[] = { + " 0: 0123 lsls r3, r4, #4\n", + " 2: 0963 lsrs r3, r4, #5\n", + " 4: 11a3 asrs r3, r4, #6\n", + " 6: ea4f 13f4 mov.w r3, r4, ror #7\n", + " a: 41e3 rors r3, r4\n", + " c: 0128 lsls r0, r5, #4\n", + " e: 0968 lsrs r0, r5, #5\n", + " 10: 11a8 asrs r0, r5, #6\n", + " 12: ea4f 18f4 mov.w r8, r4, ror #7\n", + " 16: ea4f 0834 mov.w r8, r4, rrx\n", + nullptr +}; +const char* BasicLoadResults[] = { + " 0: 69a3 ldr r3, [r4, #24]\n", + " 2: 7e23 ldrb r3, [r4, #24]\n", + " 4: 8b23 ldrh r3, [r4, #24]\n", + " 6: f994 3018 ldrsb.w r3, [r4, #24]\n", + " a: f9b4 3018 ldrsh.w r3, [r4, #24]\n", + " e: 9b06 ldr r3, [sp, #24]\n", + " 10: f8d4 8018 ldr.w r8, [r4, #24]\n", + " 14: f894 8018 ldrb.w r8, [r4, #24]\n", + " 18: f8b4 8018 ldrh.w r8, [r4, #24]\n", + " 1c: f994 8018 ldrsb.w r8, [r4, #24]\n", + " 20: f9b4 8018 ldrsh.w r8, [r4, #24]\n", + nullptr +}; +const char* BasicStoreResults[] = { + " 0: 61a3 str r3, [r4, #24]\n", + " 2: 7623 strb r3, [r4, #24]\n", + " 4: 8323 strh r3, [r4, #24]\n", + " 6: 9306 str r3, [sp, #24]\n", + " 8: f8c4 8018 str.w r8, [r4, #24]\n", + " c: f884 8018 strb.w r8, [r4, #24]\n", + " 10: f8a4 8018 strh.w r8, [r4, #24]\n", + nullptr +}; +const char* ComplexLoadResults[] = { + " 0: 69a3 ldr r3, [r4, #24]\n", + " 2: f854 3f18 ldr.w r3, [r4, #24]!\n", + " 6: f854 3b18 ldr.w r3, [r4], #24\n", + " a: f854 3c18 ldr.w r3, [r4, #-24]\n", + " e: f854 3d18 ldr.w r3, [r4, #-24]!\n", + " 12: f854 3918 ldr.w r3, [r4], #-24\n", + " 16: 7e23 ldrb r3, [r4, #24]\n", + " 18: f814 3f18 ldrb.w r3, [r4, #24]!\n", + " 1c: f814 3b18 ldrb.w r3, [r4], #24\n", + " 20: f814 3c18 ldrb.w r3, [r4, #-24]\n", + " 24: f814 3d18 ldrb.w r3, [r4, #-24]!\n", + " 28: f814 3918 ldrb.w r3, [r4], #-24\n", + " 2c: 8b23 ldrh r3, [r4, #24]\n", + " 2e: f834 3f18 ldrh.w r3, [r4, #24]!\n", + " 32: f834 3b18 ldrh.w r3, [r4], #24\n", + " 36: f834 3c18 ldrh.w r3, [r4, #-24]\n", + " 3a: f834 3d18 ldrh.w r3, [r4, #-24]!\n", + " 3e: f834 3918 ldrh.w r3, [r4], #-24\n", + " 42: f994 3018 ldrsb.w r3, [r4, #24]\n", + " 46: f914 3f18 ldrsb.w r3, [r4, #24]!\n", + " 4a: f914 3b18 ldrsb.w r3, [r4], #24\n", + " 4e: f914 3c18 ldrsb.w r3, [r4, #-24]\n", + " 52: f914 3d18 ldrsb.w r3, [r4, #-24]!\n", + " 56: f914 3918 ldrsb.w r3, [r4], #-24\n", + " 5a: f9b4 3018 ldrsh.w r3, [r4, #24]\n", + " 5e: f934 3f18 ldrsh.w r3, [r4, #24]!\n", + " 62: f934 3b18 ldrsh.w r3, [r4], #24\n", + " 66: f934 3c18 ldrsh.w r3, [r4, #-24]\n", + " 6a: f934 3d18 ldrsh.w r3, [r4, #-24]!\n", + " 6e: f934 3918 ldrsh.w r3, [r4], #-24\n", + nullptr +}; +const char* ComplexStoreResults[] = { + " 0: 61a3 str r3, [r4, #24]\n", + " 2: f844 3f18 str.w r3, [r4, #24]!\n", + " 6: f844 3b18 str.w r3, [r4], #24\n", + " a: f844 3c18 str.w r3, [r4, #-24]\n", + " e: f844 3d18 str.w r3, [r4, #-24]!\n", + " 12: f844 3918 str.w r3, [r4], #-24\n", + " 16: 7623 strb r3, [r4, #24]\n", + " 18: f804 3f18 strb.w r3, [r4, #24]!\n", + " 1c: f804 3b18 strb.w r3, [r4], #24\n", + " 20: f804 3c18 strb.w r3, [r4, #-24]\n", + " 24: f804 3d18 strb.w r3, [r4, #-24]!\n", + " 28: f804 3918 strb.w r3, [r4], #-24\n", + " 2c: 8323 strh r3, [r4, #24]\n", + " 2e: f824 3f18 strh.w r3, [r4, #24]!\n", + " 32: f824 3b18 strh.w r3, [r4], #24\n", + " 36: f824 3c18 strh.w r3, [r4, #-24]\n", + " 3a: f824 3d18 strh.w r3, [r4, #-24]!\n", + " 3e: f824 3918 strh.w r3, [r4], #-24\n", + nullptr +}; +const char* NegativeLoadStoreResults[] = { + " 0: f854 3c18 ldr.w r3, [r4, #-24]\n", + " 4: f854 3d18 ldr.w r3, [r4, #-24]!\n", + " 8: f854 3918 ldr.w r3, [r4], #-24\n", + " c: f854 3e18 ldrt r3, [r4, #24]\n", + " 10: f854 3f18 ldr.w r3, [r4, #24]!\n", + " 14: f854 3b18 ldr.w r3, [r4], #24\n", + " 18: f814 3c18 ldrb.w r3, [r4, #-24]\n", + " 1c: f814 3d18 ldrb.w r3, [r4, #-24]!\n", + " 20: f814 3918 ldrb.w r3, [r4], #-24\n", + " 24: f814 3e18 ldrbt r3, [r4, #24]\n", + " 28: f814 3f18 ldrb.w r3, [r4, #24]!\n", + " 2c: f814 3b18 ldrb.w r3, [r4], #24\n", + " 30: f834 3c18 ldrh.w r3, [r4, #-24]\n", + " 34: f834 3d18 ldrh.w r3, [r4, #-24]!\n", + " 38: f834 3918 ldrh.w r3, [r4], #-24\n", + " 3c: f834 3e18 ldrht r3, [r4, #24]\n", + " 40: f834 3f18 ldrh.w r3, [r4, #24]!\n", + " 44: f834 3b18 ldrh.w r3, [r4], #24\n", + " 48: f914 3c18 ldrsb.w r3, [r4, #-24]\n", + " 4c: f914 3d18 ldrsb.w r3, [r4, #-24]!\n", + " 50: f914 3918 ldrsb.w r3, [r4], #-24\n", + " 54: f914 3e18 ldrsbt r3, [r4, #24]\n", + " 58: f914 3f18 ldrsb.w r3, [r4, #24]!\n", + " 5c: f914 3b18 ldrsb.w r3, [r4], #24\n", + " 60: f934 3c18 ldrsh.w r3, [r4, #-24]\n", + " 64: f934 3d18 ldrsh.w r3, [r4, #-24]!\n", + " 68: f934 3918 ldrsh.w r3, [r4], #-24\n", + " 6c: f934 3e18 ldrsht r3, [r4, #24]\n", + " 70: f934 3f18 ldrsh.w r3, [r4, #24]!\n", + " 74: f934 3b18 ldrsh.w r3, [r4], #24\n", + " 78: f844 3c18 str.w r3, [r4, #-24]\n", + " 7c: f844 3d18 str.w r3, [r4, #-24]!\n", + " 80: f844 3918 str.w r3, [r4], #-24\n", + " 84: f844 3e18 strt r3, [r4, #24]\n", + " 88: f844 3f18 str.w r3, [r4, #24]!\n", + " 8c: f844 3b18 str.w r3, [r4], #24\n", + " 90: f804 3c18 strb.w r3, [r4, #-24]\n", + " 94: f804 3d18 strb.w r3, [r4, #-24]!\n", + " 98: f804 3918 strb.w r3, [r4], #-24\n", + " 9c: f804 3e18 strbt r3, [r4, #24]\n", + " a0: f804 3f18 strb.w r3, [r4, #24]!\n", + " a4: f804 3b18 strb.w r3, [r4], #24\n", + " a8: f824 3c18 strh.w r3, [r4, #-24]\n", + " ac: f824 3d18 strh.w r3, [r4, #-24]!\n", + " b0: f824 3918 strh.w r3, [r4], #-24\n", + " b4: f824 3e18 strht r3, [r4, #24]\n", + " b8: f824 3f18 strh.w r3, [r4, #24]!\n", + " bc: f824 3b18 strh.w r3, [r4], #24\n", + nullptr +}; +const char* SimpleLoadStoreDualResults[] = { + " 0: e9c0 2306 strd r2, r3, [r0, #24]\n", + " 4: e9d0 2306 ldrd r2, r3, [r0, #24]\n", + nullptr +}; +const char* ComplexLoadStoreDualResults[] = { + " 0: e9c0 2306 strd r2, r3, [r0, #24]\n", + " 4: e9e0 2306 strd r2, r3, [r0, #24]!\n", + " 8: e8e0 2306 strd r2, r3, [r0], #24\n", + " c: e940 2306 strd r2, r3, [r0, #-24]\n", + " 10: e960 2306 strd r2, r3, [r0, #-24]!\n", + " 14: e860 2306 strd r2, r3, [r0], #-24\n", + " 18: e9d0 2306 ldrd r2, r3, [r0, #24]\n", + " 1c: e9f0 2306 ldrd r2, r3, [r0, #24]!\n", + " 20: e8f0 2306 ldrd r2, r3, [r0], #24\n", + " 24: e950 2306 ldrd r2, r3, [r0, #-24]\n", + " 28: e970 2306 ldrd r2, r3, [r0, #-24]!\n", + " 2c: e870 2306 ldrd r2, r3, [r0], #-24\n", + nullptr +}; +const char* NegativeLoadStoreDualResults[] = { + " 0: e940 2306 strd r2, r3, [r0, #-24]\n", + " 4: e960 2306 strd r2, r3, [r0, #-24]!\n", + " 8: e860 2306 strd r2, r3, [r0], #-24\n", + " c: e9c0 2306 strd r2, r3, [r0, #24]\n", + " 10: e9e0 2306 strd r2, r3, [r0, #24]!\n", + " 14: e8e0 2306 strd r2, r3, [r0], #24\n", + " 18: e950 2306 ldrd r2, r3, [r0, #-24]\n", + " 1c: e970 2306 ldrd r2, r3, [r0, #-24]!\n", + " 20: e870 2306 ldrd r2, r3, [r0], #-24\n", + " 24: e9d0 2306 ldrd r2, r3, [r0, #24]\n", + " 28: e9f0 2306 ldrd r2, r3, [r0, #24]!\n", + " 2c: e8f0 2306 ldrd r2, r3, [r0], #24\n", + nullptr +}; +const char* SimpleBranchResults[] = { + " 0: 2002 movs r0, #2\n", + " 2: 2101 movs r1, #1\n", + " 4: e7fd b.n 2 <SimpleBranch+0x2>\n", + " 6: e000 b.n a <SimpleBranch+0xa>\n", + " 8: 2102 movs r1, #2\n", + " a: 2003 movs r0, #3\n", + " c: 2002 movs r0, #2\n", + " e: 2101 movs r1, #1\n", + " 10: d0fd beq.n e <SimpleBranch+0xe>\n", + " 12: d000 beq.n 16 <SimpleBranch+0x16>\n", + " 14: 2102 movs r1, #2\n", + " 16: 2003 movs r0, #3\n", + " 18: e002 b.n 20 <SimpleBranch+0x20>\n", + " 1a: 2104 movs r1, #4\n", + " 1c: e000 b.n 20 <SimpleBranch+0x20>\n", + " 1e: 2105 movs r1, #5\n", + " 20: 2006 movs r0, #6\n", + nullptr +}; +const char* LongBranchResults[] = { + " 0: f04f 0002 mov.w r0, #2\n", + " 4: f04f 0101 mov.w r1, #1\n", + " 8: f7ff bffc b.w 4 <LongBranch+0x4>\n", + " c: f000 b802 b.w 14 <LongBranch+0x14>\n", + " 10: f04f 0102 mov.w r1, #2\n", + " 14: f04f 0003 mov.w r0, #3\n", + " 18: f04f 0002 mov.w r0, #2\n", + " 1c: f04f 0101 mov.w r1, #1\n", + " 20: f43f affc beq.w 1c <LongBranch+0x1c>\n", + " 24: f000 8002 beq.w 2c <LongBranch+0x2c>\n", + " 28: f04f 0102 mov.w r1, #2\n", + " 2c: f04f 0003 mov.w r0, #3\n", + " 30: f000 b806 b.w 40 <LongBranch+0x40>\n", + " 34: f04f 0104 mov.w r1, #4\n", + " 38: f000 b802 b.w 40 <LongBranch+0x40>\n", + " 3c: f04f 0105 mov.w r1, #5\n", + " 40: f04f 0006 mov.w r0, #6\n", + nullptr +}; +const char* LoadMultipleResults[] = { + " 0: cc09 ldmia r4!, {r0, r3}\n", + " 2: e934 4800 ldmdb r4!, {fp, lr}\n", + " 6: e914 4800 ldmdb r4, {fp, lr}\n", + " a: f854 5b04 ldr.w r5, [r4], #4\n", + nullptr +}; +const char* StoreMultipleResults[] = { + " 0: c409 stmia r4!, {r0, r3}\n", + " 2: e8a4 4800 stmia.w r4!, {fp, lr}\n", + " 6: e884 4800 stmia.w r4, {fp, lr}\n", + " a: f844 5c04 str.w r5, [r4, #-4]\n", + " e: f844 5d04 str.w r5, [r4, #-4]!\n", + nullptr +}; +const char* MovWMovTResults[] = { + " 0: 2400 movs r4, #0\n", + " 2: 2434 movs r4, #52 ; 0x34\n", + " 4: f240 0934 movw r9, #52 ; 0x34\n", + " 8: f241 2334 movw r3, #4660 ; 0x1234\n", + " c: f64f 79ff movw r9, #65535 ; 0xffff\n", + " 10: f2c0 0000 movt r0, #0\n", + " 14: f2c1 2034 movt r0, #4660 ; 0x1234\n", + " 18: f6cf 71ff movt r1, #65535 ; 0xffff\n", + nullptr +}; +const char* SpecialAddSubResults[] = { + " 0: f20d 0250 addw r2, sp, #80 ; 0x50\n", + " 4: f20d 0d50 addw sp, sp, #80 ; 0x50\n", + " 8: f20d 0850 addw r8, sp, #80 ; 0x50\n", + " c: f60d 7200 addw r2, sp, #3840 ; 0xf00\n", + " 10: f60d 7d00 addw sp, sp, #3840 ; 0xf00\n", + " 14: f2ad 0d50 subw sp, sp, #80 ; 0x50\n", + " 18: f2ad 0050 subw r0, sp, #80 ; 0x50\n", + " 1c: f2ad 0850 subw r8, sp, #80 ; 0x50\n", + " 20: f6ad 7d00 subw sp, sp, #3840 ; 0xf00\n", + nullptr +}; +const char* StoreToOffsetResults[] = { + " 0: 60e2 str r2, [r4, #12]\n", + " 2: f44f 5c00 mov.w ip, #8192 ; 0x2000\n", + " 6: 44a4 add ip, r4\n", + " 8: f8cc 2000 str.w r2, [ip]\n", + nullptr +}; +const char* IfThenResults[] = { + " 0: bf08 it eq\n", + " 2: 2101 moveq r1, #1\n", + " 4: bf04 itt eq\n", + " 6: 2101 moveq r1, #1\n", + " 8: 2202 moveq r2, #2\n", + " a: bf0c ite eq\n", + " c: 2101 moveq r1, #1\n", + " e: 2202 movne r2, #2\n", + " 10: bf06 itte eq\n", + " 12: 2101 moveq r1, #1\n", + " 14: 2202 moveq r2, #2\n", + " 16: 2303 movne r3, #3\n", + " 18: bf0e itee eq\n", + " 1a: 2101 moveq r1, #1\n", + " 1c: 2202 movne r2, #2\n", + " 1e: 2303 movne r3, #3\n", + " 20: bf03 ittte eq\n", + " 22: 2101 moveq r1, #1\n", + " 24: 2202 moveq r2, #2\n", + " 26: 2303 moveq r3, #3\n", + " 28: 2404 movne r4, #4\n", + nullptr +}; +const char* CbzCbnzResults[] = { + " 0: b10a cbz r2, 6 <CbzCbnz+0x6>\n", + " 2: 2103 movs r1, #3\n", + " 4: 2203 movs r2, #3\n", + " 6: 2204 movs r2, #4\n", + " 8: b912 cbnz r2, 10 <CbzCbnz+0x10>\n", + " a: f04f 0803 mov.w r8, #3\n", + " e: 2203 movs r2, #3\n", + " 10: 2204 movs r2, #4\n", + nullptr +}; +const char* MultiplyResults[] = { + " 0: 4348 muls r0, r1\n", + " 2: fb01 f002 mul.w r0, r1, r2\n", + " 6: fb09 f808 mul.w r8, r9, r8\n", + " a: fb09 f80a mul.w r8, r9, sl\n", + " e: fb01 3002 mla r0, r1, r2, r3\n", + " 12: fb09 9808 mla r8, r9, r8, r9\n", + " 16: fb01 3012 mls r0, r1, r2, r3\n", + " 1a: fb09 9818 mls r8, r9, r8, r9\n", + " 1e: fba2 0103 umull r0, r1, r2, r3\n", + " 22: fbaa 890b umull r8, r9, sl, fp\n", + nullptr +}; +const char* DivideResults[] = { + " 0: fb91 f0f2 sdiv r0, r1, r2\n", + " 4: fb99 f8fa sdiv r8, r9, sl\n", + " 8: fbb1 f0f2 udiv r0, r1, r2\n", + " c: fbb9 f8fa udiv r8, r9, sl\n", + nullptr +}; +const char* VMovResults[] = { + " 0: eef7 0a00 vmov.f32 s1, #112 ; 0x70\n", + " 4: eeb7 1b00 vmov.f64 d1, #112 ; 0x70\n", + " 8: eef0 0a41 vmov.f32 s1, s2\n", + " c: eeb0 1b42 vmov.f64 d1, d2\n", + nullptr +}; +const char* BasicFloatingPointResults[] = { + " 0: ee30 0a81 vadd.f32 s0, s1, s2\n", + " 4: ee30 0ac1 vsub.f32 s0, s1, s2\n", + " 8: ee20 0a81 vmul.f32 s0, s1, s2\n", + " c: ee00 0a81 vmla.f32 s0, s1, s2\n", + " 10: ee00 0ac1 vmls.f32 s0, s1, s2\n", + " 14: ee80 0a81 vdiv.f32 s0, s1, s2\n", + " 18: eeb0 0ae0 vabs.f32 s0, s1\n", + " 1c: eeb1 0a60 vneg.f32 s0, s1\n", + " 20: eeb1 0ae0 vsqrt.f32 s0, s1\n", + " 24: ee31 0b02 vadd.f64 d0, d1, d2\n", + " 28: ee31 0b42 vsub.f64 d0, d1, d2\n", + " 2c: ee21 0b02 vmul.f64 d0, d1, d2\n", + " 30: ee01 0b02 vmla.f64 d0, d1, d2\n", + " 34: ee01 0b42 vmls.f64 d0, d1, d2\n", + " 38: ee81 0b02 vdiv.f64 d0, d1, d2\n", + " 3c: eeb0 0bc1 vabs.f64 d0, d1\n", + " 40: eeb1 0b41 vneg.f64 d0, d1\n", + " 44: eeb1 0bc1 vsqrt.f64 d0, d1\n", + nullptr +}; +const char* FloatingPointConversionsResults[] = { + " 0: eeb7 1bc2 vcvt.f32.f64 s2, d2\n", + " 4: eeb7 2ac1 vcvt.f64.f32 d2, s2\n", + " 8: eefd 0ac1 vcvt.s32.f32 s1, s2\n", + " c: eef8 0ac1 vcvt.f32.s32 s1, s2\n", + " 10: eefd 0bc2 vcvt.s32.f64 s1, d2\n", + " 14: eeb8 1bc1 vcvt.f64.s32 d1, s2\n", + " 18: eefc 0ac1 vcvt.u32.f32 s1, s2\n", + " 1c: eef8 0a41 vcvt.f32.u32 s1, s2\n", + " 20: eefc 0bc2 vcvt.u32.f64 s1, d2\n", + " 24: eeb8 1b41 vcvt.f64.u32 d1, s2\n", + nullptr +}; +const char* FloatingPointComparisonsResults[] = { + " 0: eeb4 0a60 vcmp.f32 s0, s1\n", + " 4: eeb4 0b41 vcmp.f64 d0, d1\n", + " 8: eeb5 1a40 vcmp.f32 s2, #0.0\n", + " c: eeb5 2b40 vcmp.f64 d2, #0.0\n", + nullptr +}; +const char* CallsResults[] = { + " 0: 47f0 blx lr\n", + " 2: 4770 bx lr\n", + nullptr +}; +const char* BreakpointResults[] = { + " 0: be00 bkpt 0x0000\n", + nullptr +}; +const char* StrR1Results[] = { + " 0: 9111 str r1, [sp, #68] ; 0x44\n", + " 2: f8cd 142c str.w r1, [sp, #1068] ; 0x42c\n", + nullptr +}; +const char* VPushPopResults[] = { + " 0: ed2d 1a04 vpush {s2-s5}\n", + " 4: ed2d 2b08 vpush {d2-d5}\n", + " 8: ecbd 1a04 vpop {s2-s5}\n", + " c: ecbd 2b08 vpop {d2-d5}\n", + nullptr +}; +const char* Max16BitBranchResults[] = { + " 0: e3ff b.n 802 <Max16BitBranch+0x802>\n", + " 2: 2300 movs r3, #0\n", + " 4: 2302 movs r3, #2\n", + " 6: 2304 movs r3, #4\n", + " 8: 2306 movs r3, #6\n", + " a: 2308 movs r3, #8\n", + " c: 230a movs r3, #10\n", + " e: 230c movs r3, #12\n", + " 10: 230e movs r3, #14\n", + " 12: 2310 movs r3, #16\n", + " 14: 2312 movs r3, #18\n", + " 16: 2314 movs r3, #20\n", + " 18: 2316 movs r3, #22\n", + " 1a: 2318 movs r3, #24\n", + " 1c: 231a movs r3, #26\n", + " 1e: 231c movs r3, #28\n", + " 20: 231e movs r3, #30\n", + " 22: 2320 movs r3, #32\n", + " 24: 2322 movs r3, #34 ; 0x22\n", + " 26: 2324 movs r3, #36 ; 0x24\n", + " 28: 2326 movs r3, #38 ; 0x26\n", + " 2a: 2328 movs r3, #40 ; 0x28\n", + " 2c: 232a movs r3, #42 ; 0x2a\n", + " 2e: 232c movs r3, #44 ; 0x2c\n", + " 30: 232e movs r3, #46 ; 0x2e\n", + " 32: 2330 movs r3, #48 ; 0x30\n", + " 34: 2332 movs r3, #50 ; 0x32\n", + " 36: 2334 movs r3, #52 ; 0x34\n", + " 38: 2336 movs r3, #54 ; 0x36\n", + " 3a: 2338 movs r3, #56 ; 0x38\n", + " 3c: 233a movs r3, #58 ; 0x3a\n", + " 3e: 233c movs r3, #60 ; 0x3c\n", + " 40: 233e movs r3, #62 ; 0x3e\n", + " 42: 2340 movs r3, #64 ; 0x40\n", + " 44: 2342 movs r3, #66 ; 0x42\n", + " 46: 2344 movs r3, #68 ; 0x44\n", + " 48: 2346 movs r3, #70 ; 0x46\n", + " 4a: 2348 movs r3, #72 ; 0x48\n", + " 4c: 234a movs r3, #74 ; 0x4a\n", + " 4e: 234c movs r3, #76 ; 0x4c\n", + " 50: 234e movs r3, #78 ; 0x4e\n", + " 52: 2350 movs r3, #80 ; 0x50\n", + " 54: 2352 movs r3, #82 ; 0x52\n", + " 56: 2354 movs r3, #84 ; 0x54\n", + " 58: 2356 movs r3, #86 ; 0x56\n", + " 5a: 2358 movs r3, #88 ; 0x58\n", + " 5c: 235a movs r3, #90 ; 0x5a\n", + " 5e: 235c movs r3, #92 ; 0x5c\n", + " 60: 235e movs r3, #94 ; 0x5e\n", + " 62: 2360 movs r3, #96 ; 0x60\n", + " 64: 2362 movs r3, #98 ; 0x62\n", + " 66: 2364 movs r3, #100 ; 0x64\n", + " 68: 2366 movs r3, #102 ; 0x66\n", + " 6a: 2368 movs r3, #104 ; 0x68\n", + " 6c: 236a movs r3, #106 ; 0x6a\n", + " 6e: 236c movs r3, #108 ; 0x6c\n", + " 70: 236e movs r3, #110 ; 0x6e\n", + " 72: 2370 movs r3, #112 ; 0x70\n", + " 74: 2372 movs r3, #114 ; 0x72\n", + " 76: 2374 movs r3, #116 ; 0x74\n", + " 78: 2376 movs r3, #118 ; 0x76\n", + " 7a: 2378 movs r3, #120 ; 0x78\n", + " 7c: 237a movs r3, #122 ; 0x7a\n", + " 7e: 237c movs r3, #124 ; 0x7c\n", + " 80: 237e movs r3, #126 ; 0x7e\n", + " 82: 2380 movs r3, #128 ; 0x80\n", + " 84: 2382 movs r3, #130 ; 0x82\n", + " 86: 2384 movs r3, #132 ; 0x84\n", + " 88: 2386 movs r3, #134 ; 0x86\n", + " 8a: 2388 movs r3, #136 ; 0x88\n", + " 8c: 238a movs r3, #138 ; 0x8a\n", + " 8e: 238c movs r3, #140 ; 0x8c\n", + " 90: 238e movs r3, #142 ; 0x8e\n", + " 92: 2390 movs r3, #144 ; 0x90\n", + " 94: 2392 movs r3, #146 ; 0x92\n", + " 96: 2394 movs r3, #148 ; 0x94\n", + " 98: 2396 movs r3, #150 ; 0x96\n", + " 9a: 2398 movs r3, #152 ; 0x98\n", + " 9c: 239a movs r3, #154 ; 0x9a\n", + " 9e: 239c movs r3, #156 ; 0x9c\n", + " a0: 239e movs r3, #158 ; 0x9e\n", + " a2: 23a0 movs r3, #160 ; 0xa0\n", + " a4: 23a2 movs r3, #162 ; 0xa2\n", + " a6: 23a4 movs r3, #164 ; 0xa4\n", + " a8: 23a6 movs r3, #166 ; 0xa6\n", + " aa: 23a8 movs r3, #168 ; 0xa8\n", + " ac: 23aa movs r3, #170 ; 0xaa\n", + " ae: 23ac movs r3, #172 ; 0xac\n", + " b0: 23ae movs r3, #174 ; 0xae\n", + " b2: 23b0 movs r3, #176 ; 0xb0\n", + " b4: 23b2 movs r3, #178 ; 0xb2\n", + " b6: 23b4 movs r3, #180 ; 0xb4\n", + " b8: 23b6 movs r3, #182 ; 0xb6\n", + " ba: 23b8 movs r3, #184 ; 0xb8\n", + " bc: 23ba movs r3, #186 ; 0xba\n", + " be: 23bc movs r3, #188 ; 0xbc\n", + " c0: 23be movs r3, #190 ; 0xbe\n", + " c2: 23c0 movs r3, #192 ; 0xc0\n", + " c4: 23c2 movs r3, #194 ; 0xc2\n", + " c6: 23c4 movs r3, #196 ; 0xc4\n", + " c8: 23c6 movs r3, #198 ; 0xc6\n", + " ca: 23c8 movs r3, #200 ; 0xc8\n", + " cc: 23ca movs r3, #202 ; 0xca\n", + " ce: 23cc movs r3, #204 ; 0xcc\n", + " d0: 23ce movs r3, #206 ; 0xce\n", + " d2: 23d0 movs r3, #208 ; 0xd0\n", + " d4: 23d2 movs r3, #210 ; 0xd2\n", + " d6: 23d4 movs r3, #212 ; 0xd4\n", + " d8: 23d6 movs r3, #214 ; 0xd6\n", + " da: 23d8 movs r3, #216 ; 0xd8\n", + " dc: 23da movs r3, #218 ; 0xda\n", + " de: 23dc movs r3, #220 ; 0xdc\n", + " e0: 23de movs r3, #222 ; 0xde\n", + " e2: 23e0 movs r3, #224 ; 0xe0\n", + " e4: 23e2 movs r3, #226 ; 0xe2\n", + " e6: 23e4 movs r3, #228 ; 0xe4\n", + " e8: 23e6 movs r3, #230 ; 0xe6\n", + " ea: 23e8 movs r3, #232 ; 0xe8\n", + " ec: 23ea movs r3, #234 ; 0xea\n", + " ee: 23ec movs r3, #236 ; 0xec\n", + " f0: 23ee movs r3, #238 ; 0xee\n", + " f2: 23f0 movs r3, #240 ; 0xf0\n", + " f4: 23f2 movs r3, #242 ; 0xf2\n", + " f6: 23f4 movs r3, #244 ; 0xf4\n", + " f8: 23f6 movs r3, #246 ; 0xf6\n", + " fa: 23f8 movs r3, #248 ; 0xf8\n", + " fc: 23fa movs r3, #250 ; 0xfa\n", + " fe: 23fc movs r3, #252 ; 0xfc\n", + " 100: 23fe movs r3, #254 ; 0xfe\n", + " 102: 2300 movs r3, #0\n", + " 104: 2302 movs r3, #2\n", + " 106: 2304 movs r3, #4\n", + " 108: 2306 movs r3, #6\n", + " 10a: 2308 movs r3, #8\n", + " 10c: 230a movs r3, #10\n", + " 10e: 230c movs r3, #12\n", + " 110: 230e movs r3, #14\n", + " 112: 2310 movs r3, #16\n", + " 114: 2312 movs r3, #18\n", + " 116: 2314 movs r3, #20\n", + " 118: 2316 movs r3, #22\n", + " 11a: 2318 movs r3, #24\n", + " 11c: 231a movs r3, #26\n", + " 11e: 231c movs r3, #28\n", + " 120: 231e movs r3, #30\n", + " 122: 2320 movs r3, #32\n", + " 124: 2322 movs r3, #34 ; 0x22\n", + " 126: 2324 movs r3, #36 ; 0x24\n", + " 128: 2326 movs r3, #38 ; 0x26\n", + " 12a: 2328 movs r3, #40 ; 0x28\n", + " 12c: 232a movs r3, #42 ; 0x2a\n", + " 12e: 232c movs r3, #44 ; 0x2c\n", + " 130: 232e movs r3, #46 ; 0x2e\n", + " 132: 2330 movs r3, #48 ; 0x30\n", + " 134: 2332 movs r3, #50 ; 0x32\n", + " 136: 2334 movs r3, #52 ; 0x34\n", + " 138: 2336 movs r3, #54 ; 0x36\n", + " 13a: 2338 movs r3, #56 ; 0x38\n", + " 13c: 233a movs r3, #58 ; 0x3a\n", + " 13e: 233c movs r3, #60 ; 0x3c\n", + " 140: 233e movs r3, #62 ; 0x3e\n", + " 142: 2340 movs r3, #64 ; 0x40\n", + " 144: 2342 movs r3, #66 ; 0x42\n", + " 146: 2344 movs r3, #68 ; 0x44\n", + " 148: 2346 movs r3, #70 ; 0x46\n", + " 14a: 2348 movs r3, #72 ; 0x48\n", + " 14c: 234a movs r3, #74 ; 0x4a\n", + " 14e: 234c movs r3, #76 ; 0x4c\n", + " 150: 234e movs r3, #78 ; 0x4e\n", + " 152: 2350 movs r3, #80 ; 0x50\n", + " 154: 2352 movs r3, #82 ; 0x52\n", + " 156: 2354 movs r3, #84 ; 0x54\n", + " 158: 2356 movs r3, #86 ; 0x56\n", + " 15a: 2358 movs r3, #88 ; 0x58\n", + " 15c: 235a movs r3, #90 ; 0x5a\n", + " 15e: 235c movs r3, #92 ; 0x5c\n", + " 160: 235e movs r3, #94 ; 0x5e\n", + " 162: 2360 movs r3, #96 ; 0x60\n", + " 164: 2362 movs r3, #98 ; 0x62\n", + " 166: 2364 movs r3, #100 ; 0x64\n", + " 168: 2366 movs r3, #102 ; 0x66\n", + " 16a: 2368 movs r3, #104 ; 0x68\n", + " 16c: 236a movs r3, #106 ; 0x6a\n", + " 16e: 236c movs r3, #108 ; 0x6c\n", + " 170: 236e movs r3, #110 ; 0x6e\n", + " 172: 2370 movs r3, #112 ; 0x70\n", + " 174: 2372 movs r3, #114 ; 0x72\n", + " 176: 2374 movs r3, #116 ; 0x74\n", + " 178: 2376 movs r3, #118 ; 0x76\n", + " 17a: 2378 movs r3, #120 ; 0x78\n", + " 17c: 237a movs r3, #122 ; 0x7a\n", + " 17e: 237c movs r3, #124 ; 0x7c\n", + " 180: 237e movs r3, #126 ; 0x7e\n", + " 182: 2380 movs r3, #128 ; 0x80\n", + " 184: 2382 movs r3, #130 ; 0x82\n", + " 186: 2384 movs r3, #132 ; 0x84\n", + " 188: 2386 movs r3, #134 ; 0x86\n", + " 18a: 2388 movs r3, #136 ; 0x88\n", + " 18c: 238a movs r3, #138 ; 0x8a\n", + " 18e: 238c movs r3, #140 ; 0x8c\n", + " 190: 238e movs r3, #142 ; 0x8e\n", + " 192: 2390 movs r3, #144 ; 0x90\n", + " 194: 2392 movs r3, #146 ; 0x92\n", + " 196: 2394 movs r3, #148 ; 0x94\n", + " 198: 2396 movs r3, #150 ; 0x96\n", + " 19a: 2398 movs r3, #152 ; 0x98\n", + " 19c: 239a movs r3, #154 ; 0x9a\n", + " 19e: 239c movs r3, #156 ; 0x9c\n", + " 1a0: 239e movs r3, #158 ; 0x9e\n", + " 1a2: 23a0 movs r3, #160 ; 0xa0\n", + " 1a4: 23a2 movs r3, #162 ; 0xa2\n", + " 1a6: 23a4 movs r3, #164 ; 0xa4\n", + " 1a8: 23a6 movs r3, #166 ; 0xa6\n", + " 1aa: 23a8 movs r3, #168 ; 0xa8\n", + " 1ac: 23aa movs r3, #170 ; 0xaa\n", + " 1ae: 23ac movs r3, #172 ; 0xac\n", + " 1b0: 23ae movs r3, #174 ; 0xae\n", + " 1b2: 23b0 movs r3, #176 ; 0xb0\n", + " 1b4: 23b2 movs r3, #178 ; 0xb2\n", + " 1b6: 23b4 movs r3, #180 ; 0xb4\n", + " 1b8: 23b6 movs r3, #182 ; 0xb6\n", + " 1ba: 23b8 movs r3, #184 ; 0xb8\n", + " 1bc: 23ba movs r3, #186 ; 0xba\n", + " 1be: 23bc movs r3, #188 ; 0xbc\n", + " 1c0: 23be movs r3, #190 ; 0xbe\n", + " 1c2: 23c0 movs r3, #192 ; 0xc0\n", + " 1c4: 23c2 movs r3, #194 ; 0xc2\n", + " 1c6: 23c4 movs r3, #196 ; 0xc4\n", + " 1c8: 23c6 movs r3, #198 ; 0xc6\n", + " 1ca: 23c8 movs r3, #200 ; 0xc8\n", + " 1cc: 23ca movs r3, #202 ; 0xca\n", + " 1ce: 23cc movs r3, #204 ; 0xcc\n", + " 1d0: 23ce movs r3, #206 ; 0xce\n", + " 1d2: 23d0 movs r3, #208 ; 0xd0\n", + " 1d4: 23d2 movs r3, #210 ; 0xd2\n", + " 1d6: 23d4 movs r3, #212 ; 0xd4\n", + " 1d8: 23d6 movs r3, #214 ; 0xd6\n", + " 1da: 23d8 movs r3, #216 ; 0xd8\n", + " 1dc: 23da movs r3, #218 ; 0xda\n", + " 1de: 23dc movs r3, #220 ; 0xdc\n", + " 1e0: 23de movs r3, #222 ; 0xde\n", + " 1e2: 23e0 movs r3, #224 ; 0xe0\n", + " 1e4: 23e2 movs r3, #226 ; 0xe2\n", + " 1e6: 23e4 movs r3, #228 ; 0xe4\n", + " 1e8: 23e6 movs r3, #230 ; 0xe6\n", + " 1ea: 23e8 movs r3, #232 ; 0xe8\n", + " 1ec: 23ea movs r3, #234 ; 0xea\n", + " 1ee: 23ec movs r3, #236 ; 0xec\n", + " 1f0: 23ee movs r3, #238 ; 0xee\n", + " 1f2: 23f0 movs r3, #240 ; 0xf0\n", + " 1f4: 23f2 movs r3, #242 ; 0xf2\n", + " 1f6: 23f4 movs r3, #244 ; 0xf4\n", + " 1f8: 23f6 movs r3, #246 ; 0xf6\n", + " 1fa: 23f8 movs r3, #248 ; 0xf8\n", + " 1fc: 23fa movs r3, #250 ; 0xfa\n", + " 1fe: 23fc movs r3, #252 ; 0xfc\n", + " 200: 23fe movs r3, #254 ; 0xfe\n", + " 202: 2300 movs r3, #0\n", + " 204: 2302 movs r3, #2\n", + " 206: 2304 movs r3, #4\n", + " 208: 2306 movs r3, #6\n", + " 20a: 2308 movs r3, #8\n", + " 20c: 230a movs r3, #10\n", + " 20e: 230c movs r3, #12\n", + " 210: 230e movs r3, #14\n", + " 212: 2310 movs r3, #16\n", + " 214: 2312 movs r3, #18\n", + " 216: 2314 movs r3, #20\n", + " 218: 2316 movs r3, #22\n", + " 21a: 2318 movs r3, #24\n", + " 21c: 231a movs r3, #26\n", + " 21e: 231c movs r3, #28\n", + " 220: 231e movs r3, #30\n", + " 222: 2320 movs r3, #32\n", + " 224: 2322 movs r3, #34 ; 0x22\n", + " 226: 2324 movs r3, #36 ; 0x24\n", + " 228: 2326 movs r3, #38 ; 0x26\n", + " 22a: 2328 movs r3, #40 ; 0x28\n", + " 22c: 232a movs r3, #42 ; 0x2a\n", + " 22e: 232c movs r3, #44 ; 0x2c\n", + " 230: 232e movs r3, #46 ; 0x2e\n", + " 232: 2330 movs r3, #48 ; 0x30\n", + " 234: 2332 movs r3, #50 ; 0x32\n", + " 236: 2334 movs r3, #52 ; 0x34\n", + " 238: 2336 movs r3, #54 ; 0x36\n", + " 23a: 2338 movs r3, #56 ; 0x38\n", + " 23c: 233a movs r3, #58 ; 0x3a\n", + " 23e: 233c movs r3, #60 ; 0x3c\n", + " 240: 233e movs r3, #62 ; 0x3e\n", + " 242: 2340 movs r3, #64 ; 0x40\n", + " 244: 2342 movs r3, #66 ; 0x42\n", + " 246: 2344 movs r3, #68 ; 0x44\n", + " 248: 2346 movs r3, #70 ; 0x46\n", + " 24a: 2348 movs r3, #72 ; 0x48\n", + " 24c: 234a movs r3, #74 ; 0x4a\n", + " 24e: 234c movs r3, #76 ; 0x4c\n", + " 250: 234e movs r3, #78 ; 0x4e\n", + " 252: 2350 movs r3, #80 ; 0x50\n", + " 254: 2352 movs r3, #82 ; 0x52\n", + " 256: 2354 movs r3, #84 ; 0x54\n", + " 258: 2356 movs r3, #86 ; 0x56\n", + " 25a: 2358 movs r3, #88 ; 0x58\n", + " 25c: 235a movs r3, #90 ; 0x5a\n", + " 25e: 235c movs r3, #92 ; 0x5c\n", + " 260: 235e movs r3, #94 ; 0x5e\n", + " 262: 2360 movs r3, #96 ; 0x60\n", + " 264: 2362 movs r3, #98 ; 0x62\n", + " 266: 2364 movs r3, #100 ; 0x64\n", + " 268: 2366 movs r3, #102 ; 0x66\n", + " 26a: 2368 movs r3, #104 ; 0x68\n", + " 26c: 236a movs r3, #106 ; 0x6a\n", + " 26e: 236c movs r3, #108 ; 0x6c\n", + " 270: 236e movs r3, #110 ; 0x6e\n", + " 272: 2370 movs r3, #112 ; 0x70\n", + " 274: 2372 movs r3, #114 ; 0x72\n", + " 276: 2374 movs r3, #116 ; 0x74\n", + " 278: 2376 movs r3, #118 ; 0x76\n", + " 27a: 2378 movs r3, #120 ; 0x78\n", + " 27c: 237a movs r3, #122 ; 0x7a\n", + " 27e: 237c movs r3, #124 ; 0x7c\n", + " 280: 237e movs r3, #126 ; 0x7e\n", + " 282: 2380 movs r3, #128 ; 0x80\n", + " 284: 2382 movs r3, #130 ; 0x82\n", + " 286: 2384 movs r3, #132 ; 0x84\n", + " 288: 2386 movs r3, #134 ; 0x86\n", + " 28a: 2388 movs r3, #136 ; 0x88\n", + " 28c: 238a movs r3, #138 ; 0x8a\n", + " 28e: 238c movs r3, #140 ; 0x8c\n", + " 290: 238e movs r3, #142 ; 0x8e\n", + " 292: 2390 movs r3, #144 ; 0x90\n", + " 294: 2392 movs r3, #146 ; 0x92\n", + " 296: 2394 movs r3, #148 ; 0x94\n", + " 298: 2396 movs r3, #150 ; 0x96\n", + " 29a: 2398 movs r3, #152 ; 0x98\n", + " 29c: 239a movs r3, #154 ; 0x9a\n", + " 29e: 239c movs r3, #156 ; 0x9c\n", + " 2a0: 239e movs r3, #158 ; 0x9e\n", + " 2a2: 23a0 movs r3, #160 ; 0xa0\n", + " 2a4: 23a2 movs r3, #162 ; 0xa2\n", + " 2a6: 23a4 movs r3, #164 ; 0xa4\n", + " 2a8: 23a6 movs r3, #166 ; 0xa6\n", + " 2aa: 23a8 movs r3, #168 ; 0xa8\n", + " 2ac: 23aa movs r3, #170 ; 0xaa\n", + " 2ae: 23ac movs r3, #172 ; 0xac\n", + " 2b0: 23ae movs r3, #174 ; 0xae\n", + " 2b2: 23b0 movs r3, #176 ; 0xb0\n", + " 2b4: 23b2 movs r3, #178 ; 0xb2\n", + " 2b6: 23b4 movs r3, #180 ; 0xb4\n", + " 2b8: 23b6 movs r3, #182 ; 0xb6\n", + " 2ba: 23b8 movs r3, #184 ; 0xb8\n", + " 2bc: 23ba movs r3, #186 ; 0xba\n", + " 2be: 23bc movs r3, #188 ; 0xbc\n", + " 2c0: 23be movs r3, #190 ; 0xbe\n", + " 2c2: 23c0 movs r3, #192 ; 0xc0\n", + " 2c4: 23c2 movs r3, #194 ; 0xc2\n", + " 2c6: 23c4 movs r3, #196 ; 0xc4\n", + " 2c8: 23c6 movs r3, #198 ; 0xc6\n", + " 2ca: 23c8 movs r3, #200 ; 0xc8\n", + " 2cc: 23ca movs r3, #202 ; 0xca\n", + " 2ce: 23cc movs r3, #204 ; 0xcc\n", + " 2d0: 23ce movs r3, #206 ; 0xce\n", + " 2d2: 23d0 movs r3, #208 ; 0xd0\n", + " 2d4: 23d2 movs r3, #210 ; 0xd2\n", + " 2d6: 23d4 movs r3, #212 ; 0xd4\n", + " 2d8: 23d6 movs r3, #214 ; 0xd6\n", + " 2da: 23d8 movs r3, #216 ; 0xd8\n", + " 2dc: 23da movs r3, #218 ; 0xda\n", + " 2de: 23dc movs r3, #220 ; 0xdc\n", + " 2e0: 23de movs r3, #222 ; 0xde\n", + " 2e2: 23e0 movs r3, #224 ; 0xe0\n", + " 2e4: 23e2 movs r3, #226 ; 0xe2\n", + " 2e6: 23e4 movs r3, #228 ; 0xe4\n", + " 2e8: 23e6 movs r3, #230 ; 0xe6\n", + " 2ea: 23e8 movs r3, #232 ; 0xe8\n", + " 2ec: 23ea movs r3, #234 ; 0xea\n", + " 2ee: 23ec movs r3, #236 ; 0xec\n", + " 2f0: 23ee movs r3, #238 ; 0xee\n", + " 2f2: 23f0 movs r3, #240 ; 0xf0\n", + " 2f4: 23f2 movs r3, #242 ; 0xf2\n", + " 2f6: 23f4 movs r3, #244 ; 0xf4\n", + " 2f8: 23f6 movs r3, #246 ; 0xf6\n", + " 2fa: 23f8 movs r3, #248 ; 0xf8\n", + " 2fc: 23fa movs r3, #250 ; 0xfa\n", + " 2fe: 23fc movs r3, #252 ; 0xfc\n", + " 300: 23fe movs r3, #254 ; 0xfe\n", + " 302: 2300 movs r3, #0\n", + " 304: 2302 movs r3, #2\n", + " 306: 2304 movs r3, #4\n", + " 308: 2306 movs r3, #6\n", + " 30a: 2308 movs r3, #8\n", + " 30c: 230a movs r3, #10\n", + " 30e: 230c movs r3, #12\n", + " 310: 230e movs r3, #14\n", + " 312: 2310 movs r3, #16\n", + " 314: 2312 movs r3, #18\n", + " 316: 2314 movs r3, #20\n", + " 318: 2316 movs r3, #22\n", + " 31a: 2318 movs r3, #24\n", + " 31c: 231a movs r3, #26\n", + " 31e: 231c movs r3, #28\n", + " 320: 231e movs r3, #30\n", + " 322: 2320 movs r3, #32\n", + " 324: 2322 movs r3, #34 ; 0x22\n", + " 326: 2324 movs r3, #36 ; 0x24\n", + " 328: 2326 movs r3, #38 ; 0x26\n", + " 32a: 2328 movs r3, #40 ; 0x28\n", + " 32c: 232a movs r3, #42 ; 0x2a\n", + " 32e: 232c movs r3, #44 ; 0x2c\n", + " 330: 232e movs r3, #46 ; 0x2e\n", + " 332: 2330 movs r3, #48 ; 0x30\n", + " 334: 2332 movs r3, #50 ; 0x32\n", + " 336: 2334 movs r3, #52 ; 0x34\n", + " 338: 2336 movs r3, #54 ; 0x36\n", + " 33a: 2338 movs r3, #56 ; 0x38\n", + " 33c: 233a movs r3, #58 ; 0x3a\n", + " 33e: 233c movs r3, #60 ; 0x3c\n", + " 340: 233e movs r3, #62 ; 0x3e\n", + " 342: 2340 movs r3, #64 ; 0x40\n", + " 344: 2342 movs r3, #66 ; 0x42\n", + " 346: 2344 movs r3, #68 ; 0x44\n", + " 348: 2346 movs r3, #70 ; 0x46\n", + " 34a: 2348 movs r3, #72 ; 0x48\n", + " 34c: 234a movs r3, #74 ; 0x4a\n", + " 34e: 234c movs r3, #76 ; 0x4c\n", + " 350: 234e movs r3, #78 ; 0x4e\n", + " 352: 2350 movs r3, #80 ; 0x50\n", + " 354: 2352 movs r3, #82 ; 0x52\n", + " 356: 2354 movs r3, #84 ; 0x54\n", + " 358: 2356 movs r3, #86 ; 0x56\n", + " 35a: 2358 movs r3, #88 ; 0x58\n", + " 35c: 235a movs r3, #90 ; 0x5a\n", + " 35e: 235c movs r3, #92 ; 0x5c\n", + " 360: 235e movs r3, #94 ; 0x5e\n", + " 362: 2360 movs r3, #96 ; 0x60\n", + " 364: 2362 movs r3, #98 ; 0x62\n", + " 366: 2364 movs r3, #100 ; 0x64\n", + " 368: 2366 movs r3, #102 ; 0x66\n", + " 36a: 2368 movs r3, #104 ; 0x68\n", + " 36c: 236a movs r3, #106 ; 0x6a\n", + " 36e: 236c movs r3, #108 ; 0x6c\n", + " 370: 236e movs r3, #110 ; 0x6e\n", + " 372: 2370 movs r3, #112 ; 0x70\n", + " 374: 2372 movs r3, #114 ; 0x72\n", + " 376: 2374 movs r3, #116 ; 0x74\n", + " 378: 2376 movs r3, #118 ; 0x76\n", + " 37a: 2378 movs r3, #120 ; 0x78\n", + " 37c: 237a movs r3, #122 ; 0x7a\n", + " 37e: 237c movs r3, #124 ; 0x7c\n", + " 380: 237e movs r3, #126 ; 0x7e\n", + " 382: 2380 movs r3, #128 ; 0x80\n", + " 384: 2382 movs r3, #130 ; 0x82\n", + " 386: 2384 movs r3, #132 ; 0x84\n", + " 388: 2386 movs r3, #134 ; 0x86\n", + " 38a: 2388 movs r3, #136 ; 0x88\n", + " 38c: 238a movs r3, #138 ; 0x8a\n", + " 38e: 238c movs r3, #140 ; 0x8c\n", + " 390: 238e movs r3, #142 ; 0x8e\n", + " 392: 2390 movs r3, #144 ; 0x90\n", + " 394: 2392 movs r3, #146 ; 0x92\n", + " 396: 2394 movs r3, #148 ; 0x94\n", + " 398: 2396 movs r3, #150 ; 0x96\n", + " 39a: 2398 movs r3, #152 ; 0x98\n", + " 39c: 239a movs r3, #154 ; 0x9a\n", + " 39e: 239c movs r3, #156 ; 0x9c\n", + " 3a0: 239e movs r3, #158 ; 0x9e\n", + " 3a2: 23a0 movs r3, #160 ; 0xa0\n", + " 3a4: 23a2 movs r3, #162 ; 0xa2\n", + " 3a6: 23a4 movs r3, #164 ; 0xa4\n", + " 3a8: 23a6 movs r3, #166 ; 0xa6\n", + " 3aa: 23a8 movs r3, #168 ; 0xa8\n", + " 3ac: 23aa movs r3, #170 ; 0xaa\n", + " 3ae: 23ac movs r3, #172 ; 0xac\n", + " 3b0: 23ae movs r3, #174 ; 0xae\n", + " 3b2: 23b0 movs r3, #176 ; 0xb0\n", + " 3b4: 23b2 movs r3, #178 ; 0xb2\n", + " 3b6: 23b4 movs r3, #180 ; 0xb4\n", + " 3b8: 23b6 movs r3, #182 ; 0xb6\n", + " 3ba: 23b8 movs r3, #184 ; 0xb8\n", + " 3bc: 23ba movs r3, #186 ; 0xba\n", + " 3be: 23bc movs r3, #188 ; 0xbc\n", + " 3c0: 23be movs r3, #190 ; 0xbe\n", + " 3c2: 23c0 movs r3, #192 ; 0xc0\n", + " 3c4: 23c2 movs r3, #194 ; 0xc2\n", + " 3c6: 23c4 movs r3, #196 ; 0xc4\n", + " 3c8: 23c6 movs r3, #198 ; 0xc6\n", + " 3ca: 23c8 movs r3, #200 ; 0xc8\n", + " 3cc: 23ca movs r3, #202 ; 0xca\n", + " 3ce: 23cc movs r3, #204 ; 0xcc\n", + " 3d0: 23ce movs r3, #206 ; 0xce\n", + " 3d2: 23d0 movs r3, #208 ; 0xd0\n", + " 3d4: 23d2 movs r3, #210 ; 0xd2\n", + " 3d6: 23d4 movs r3, #212 ; 0xd4\n", + " 3d8: 23d6 movs r3, #214 ; 0xd6\n", + " 3da: 23d8 movs r3, #216 ; 0xd8\n", + " 3dc: 23da movs r3, #218 ; 0xda\n", + " 3de: 23dc movs r3, #220 ; 0xdc\n", + " 3e0: 23de movs r3, #222 ; 0xde\n", + " 3e2: 23e0 movs r3, #224 ; 0xe0\n", + " 3e4: 23e2 movs r3, #226 ; 0xe2\n", + " 3e6: 23e4 movs r3, #228 ; 0xe4\n", + " 3e8: 23e6 movs r3, #230 ; 0xe6\n", + " 3ea: 23e8 movs r3, #232 ; 0xe8\n", + " 3ec: 23ea movs r3, #234 ; 0xea\n", + " 3ee: 23ec movs r3, #236 ; 0xec\n", + " 3f0: 23ee movs r3, #238 ; 0xee\n", + " 3f2: 23f0 movs r3, #240 ; 0xf0\n", + " 3f4: 23f2 movs r3, #242 ; 0xf2\n", + " 3f6: 23f4 movs r3, #244 ; 0xf4\n", + " 3f8: 23f6 movs r3, #246 ; 0xf6\n", + " 3fa: 23f8 movs r3, #248 ; 0xf8\n", + " 3fc: 23fa movs r3, #250 ; 0xfa\n", + " 3fe: 23fc movs r3, #252 ; 0xfc\n", + " 400: 23fe movs r3, #254 ; 0xfe\n", + " 402: 2300 movs r3, #0\n", + " 404: 2302 movs r3, #2\n", + " 406: 2304 movs r3, #4\n", + " 408: 2306 movs r3, #6\n", + " 40a: 2308 movs r3, #8\n", + " 40c: 230a movs r3, #10\n", + " 40e: 230c movs r3, #12\n", + " 410: 230e movs r3, #14\n", + " 412: 2310 movs r3, #16\n", + " 414: 2312 movs r3, #18\n", + " 416: 2314 movs r3, #20\n", + " 418: 2316 movs r3, #22\n", + " 41a: 2318 movs r3, #24\n", + " 41c: 231a movs r3, #26\n", + " 41e: 231c movs r3, #28\n", + " 420: 231e movs r3, #30\n", + " 422: 2320 movs r3, #32\n", + " 424: 2322 movs r3, #34 ; 0x22\n", + " 426: 2324 movs r3, #36 ; 0x24\n", + " 428: 2326 movs r3, #38 ; 0x26\n", + " 42a: 2328 movs r3, #40 ; 0x28\n", + " 42c: 232a movs r3, #42 ; 0x2a\n", + " 42e: 232c movs r3, #44 ; 0x2c\n", + " 430: 232e movs r3, #46 ; 0x2e\n", + " 432: 2330 movs r3, #48 ; 0x30\n", + " 434: 2332 movs r3, #50 ; 0x32\n", + " 436: 2334 movs r3, #52 ; 0x34\n", + " 438: 2336 movs r3, #54 ; 0x36\n", + " 43a: 2338 movs r3, #56 ; 0x38\n", + " 43c: 233a movs r3, #58 ; 0x3a\n", + " 43e: 233c movs r3, #60 ; 0x3c\n", + " 440: 233e movs r3, #62 ; 0x3e\n", + " 442: 2340 movs r3, #64 ; 0x40\n", + " 444: 2342 movs r3, #66 ; 0x42\n", + " 446: 2344 movs r3, #68 ; 0x44\n", + " 448: 2346 movs r3, #70 ; 0x46\n", + " 44a: 2348 movs r3, #72 ; 0x48\n", + " 44c: 234a movs r3, #74 ; 0x4a\n", + " 44e: 234c movs r3, #76 ; 0x4c\n", + " 450: 234e movs r3, #78 ; 0x4e\n", + " 452: 2350 movs r3, #80 ; 0x50\n", + " 454: 2352 movs r3, #82 ; 0x52\n", + " 456: 2354 movs r3, #84 ; 0x54\n", + " 458: 2356 movs r3, #86 ; 0x56\n", + " 45a: 2358 movs r3, #88 ; 0x58\n", + " 45c: 235a movs r3, #90 ; 0x5a\n", + " 45e: 235c movs r3, #92 ; 0x5c\n", + " 460: 235e movs r3, #94 ; 0x5e\n", + " 462: 2360 movs r3, #96 ; 0x60\n", + " 464: 2362 movs r3, #98 ; 0x62\n", + " 466: 2364 movs r3, #100 ; 0x64\n", + " 468: 2366 movs r3, #102 ; 0x66\n", + " 46a: 2368 movs r3, #104 ; 0x68\n", + " 46c: 236a movs r3, #106 ; 0x6a\n", + " 46e: 236c movs r3, #108 ; 0x6c\n", + " 470: 236e movs r3, #110 ; 0x6e\n", + " 472: 2370 movs r3, #112 ; 0x70\n", + " 474: 2372 movs r3, #114 ; 0x72\n", + " 476: 2374 movs r3, #116 ; 0x74\n", + " 478: 2376 movs r3, #118 ; 0x76\n", + " 47a: 2378 movs r3, #120 ; 0x78\n", + " 47c: 237a movs r3, #122 ; 0x7a\n", + " 47e: 237c movs r3, #124 ; 0x7c\n", + " 480: 237e movs r3, #126 ; 0x7e\n", + " 482: 2380 movs r3, #128 ; 0x80\n", + " 484: 2382 movs r3, #130 ; 0x82\n", + " 486: 2384 movs r3, #132 ; 0x84\n", + " 488: 2386 movs r3, #134 ; 0x86\n", + " 48a: 2388 movs r3, #136 ; 0x88\n", + " 48c: 238a movs r3, #138 ; 0x8a\n", + " 48e: 238c movs r3, #140 ; 0x8c\n", + " 490: 238e movs r3, #142 ; 0x8e\n", + " 492: 2390 movs r3, #144 ; 0x90\n", + " 494: 2392 movs r3, #146 ; 0x92\n", + " 496: 2394 movs r3, #148 ; 0x94\n", + " 498: 2396 movs r3, #150 ; 0x96\n", + " 49a: 2398 movs r3, #152 ; 0x98\n", + " 49c: 239a movs r3, #154 ; 0x9a\n", + " 49e: 239c movs r3, #156 ; 0x9c\n", + " 4a0: 239e movs r3, #158 ; 0x9e\n", + " 4a2: 23a0 movs r3, #160 ; 0xa0\n", + " 4a4: 23a2 movs r3, #162 ; 0xa2\n", + " 4a6: 23a4 movs r3, #164 ; 0xa4\n", + " 4a8: 23a6 movs r3, #166 ; 0xa6\n", + " 4aa: 23a8 movs r3, #168 ; 0xa8\n", + " 4ac: 23aa movs r3, #170 ; 0xaa\n", + " 4ae: 23ac movs r3, #172 ; 0xac\n", + " 4b0: 23ae movs r3, #174 ; 0xae\n", + " 4b2: 23b0 movs r3, #176 ; 0xb0\n", + " 4b4: 23b2 movs r3, #178 ; 0xb2\n", + " 4b6: 23b4 movs r3, #180 ; 0xb4\n", + " 4b8: 23b6 movs r3, #182 ; 0xb6\n", + " 4ba: 23b8 movs r3, #184 ; 0xb8\n", + " 4bc: 23ba movs r3, #186 ; 0xba\n", + " 4be: 23bc movs r3, #188 ; 0xbc\n", + " 4c0: 23be movs r3, #190 ; 0xbe\n", + " 4c2: 23c0 movs r3, #192 ; 0xc0\n", + " 4c4: 23c2 movs r3, #194 ; 0xc2\n", + " 4c6: 23c4 movs r3, #196 ; 0xc4\n", + " 4c8: 23c6 movs r3, #198 ; 0xc6\n", + " 4ca: 23c8 movs r3, #200 ; 0xc8\n", + " 4cc: 23ca movs r3, #202 ; 0xca\n", + " 4ce: 23cc movs r3, #204 ; 0xcc\n", + " 4d0: 23ce movs r3, #206 ; 0xce\n", + " 4d2: 23d0 movs r3, #208 ; 0xd0\n", + " 4d4: 23d2 movs r3, #210 ; 0xd2\n", + " 4d6: 23d4 movs r3, #212 ; 0xd4\n", + " 4d8: 23d6 movs r3, #214 ; 0xd6\n", + " 4da: 23d8 movs r3, #216 ; 0xd8\n", + " 4dc: 23da movs r3, #218 ; 0xda\n", + " 4de: 23dc movs r3, #220 ; 0xdc\n", + " 4e0: 23de movs r3, #222 ; 0xde\n", + " 4e2: 23e0 movs r3, #224 ; 0xe0\n", + " 4e4: 23e2 movs r3, #226 ; 0xe2\n", + " 4e6: 23e4 movs r3, #228 ; 0xe4\n", + " 4e8: 23e6 movs r3, #230 ; 0xe6\n", + " 4ea: 23e8 movs r3, #232 ; 0xe8\n", + " 4ec: 23ea movs r3, #234 ; 0xea\n", + " 4ee: 23ec movs r3, #236 ; 0xec\n", + " 4f0: 23ee movs r3, #238 ; 0xee\n", + " 4f2: 23f0 movs r3, #240 ; 0xf0\n", + " 4f4: 23f2 movs r3, #242 ; 0xf2\n", + " 4f6: 23f4 movs r3, #244 ; 0xf4\n", + " 4f8: 23f6 movs r3, #246 ; 0xf6\n", + " 4fa: 23f8 movs r3, #248 ; 0xf8\n", + " 4fc: 23fa movs r3, #250 ; 0xfa\n", + " 4fe: 23fc movs r3, #252 ; 0xfc\n", + " 500: 23fe movs r3, #254 ; 0xfe\n", + " 502: 2300 movs r3, #0\n", + " 504: 2302 movs r3, #2\n", + " 506: 2304 movs r3, #4\n", + " 508: 2306 movs r3, #6\n", + " 50a: 2308 movs r3, #8\n", + " 50c: 230a movs r3, #10\n", + " 50e: 230c movs r3, #12\n", + " 510: 230e movs r3, #14\n", + " 512: 2310 movs r3, #16\n", + " 514: 2312 movs r3, #18\n", + " 516: 2314 movs r3, #20\n", + " 518: 2316 movs r3, #22\n", + " 51a: 2318 movs r3, #24\n", + " 51c: 231a movs r3, #26\n", + " 51e: 231c movs r3, #28\n", + " 520: 231e movs r3, #30\n", + " 522: 2320 movs r3, #32\n", + " 524: 2322 movs r3, #34 ; 0x22\n", + " 526: 2324 movs r3, #36 ; 0x24\n", + " 528: 2326 movs r3, #38 ; 0x26\n", + " 52a: 2328 movs r3, #40 ; 0x28\n", + " 52c: 232a movs r3, #42 ; 0x2a\n", + " 52e: 232c movs r3, #44 ; 0x2c\n", + " 530: 232e movs r3, #46 ; 0x2e\n", + " 532: 2330 movs r3, #48 ; 0x30\n", + " 534: 2332 movs r3, #50 ; 0x32\n", + " 536: 2334 movs r3, #52 ; 0x34\n", + " 538: 2336 movs r3, #54 ; 0x36\n", + " 53a: 2338 movs r3, #56 ; 0x38\n", + " 53c: 233a movs r3, #58 ; 0x3a\n", + " 53e: 233c movs r3, #60 ; 0x3c\n", + " 540: 233e movs r3, #62 ; 0x3e\n", + " 542: 2340 movs r3, #64 ; 0x40\n", + " 544: 2342 movs r3, #66 ; 0x42\n", + " 546: 2344 movs r3, #68 ; 0x44\n", + " 548: 2346 movs r3, #70 ; 0x46\n", + " 54a: 2348 movs r3, #72 ; 0x48\n", + " 54c: 234a movs r3, #74 ; 0x4a\n", + " 54e: 234c movs r3, #76 ; 0x4c\n", + " 550: 234e movs r3, #78 ; 0x4e\n", + " 552: 2350 movs r3, #80 ; 0x50\n", + " 554: 2352 movs r3, #82 ; 0x52\n", + " 556: 2354 movs r3, #84 ; 0x54\n", + " 558: 2356 movs r3, #86 ; 0x56\n", + " 55a: 2358 movs r3, #88 ; 0x58\n", + " 55c: 235a movs r3, #90 ; 0x5a\n", + " 55e: 235c movs r3, #92 ; 0x5c\n", + " 560: 235e movs r3, #94 ; 0x5e\n", + " 562: 2360 movs r3, #96 ; 0x60\n", + " 564: 2362 movs r3, #98 ; 0x62\n", + " 566: 2364 movs r3, #100 ; 0x64\n", + " 568: 2366 movs r3, #102 ; 0x66\n", + " 56a: 2368 movs r3, #104 ; 0x68\n", + " 56c: 236a movs r3, #106 ; 0x6a\n", + " 56e: 236c movs r3, #108 ; 0x6c\n", + " 570: 236e movs r3, #110 ; 0x6e\n", + " 572: 2370 movs r3, #112 ; 0x70\n", + " 574: 2372 movs r3, #114 ; 0x72\n", + " 576: 2374 movs r3, #116 ; 0x74\n", + " 578: 2376 movs r3, #118 ; 0x76\n", + " 57a: 2378 movs r3, #120 ; 0x78\n", + " 57c: 237a movs r3, #122 ; 0x7a\n", + " 57e: 237c movs r3, #124 ; 0x7c\n", + " 580: 237e movs r3, #126 ; 0x7e\n", + " 582: 2380 movs r3, #128 ; 0x80\n", + " 584: 2382 movs r3, #130 ; 0x82\n", + " 586: 2384 movs r3, #132 ; 0x84\n", + " 588: 2386 movs r3, #134 ; 0x86\n", + " 58a: 2388 movs r3, #136 ; 0x88\n", + " 58c: 238a movs r3, #138 ; 0x8a\n", + " 58e: 238c movs r3, #140 ; 0x8c\n", + " 590: 238e movs r3, #142 ; 0x8e\n", + " 592: 2390 movs r3, #144 ; 0x90\n", + " 594: 2392 movs r3, #146 ; 0x92\n", + " 596: 2394 movs r3, #148 ; 0x94\n", + " 598: 2396 movs r3, #150 ; 0x96\n", + " 59a: 2398 movs r3, #152 ; 0x98\n", + " 59c: 239a movs r3, #154 ; 0x9a\n", + " 59e: 239c movs r3, #156 ; 0x9c\n", + " 5a0: 239e movs r3, #158 ; 0x9e\n", + " 5a2: 23a0 movs r3, #160 ; 0xa0\n", + " 5a4: 23a2 movs r3, #162 ; 0xa2\n", + " 5a6: 23a4 movs r3, #164 ; 0xa4\n", + " 5a8: 23a6 movs r3, #166 ; 0xa6\n", + " 5aa: 23a8 movs r3, #168 ; 0xa8\n", + " 5ac: 23aa movs r3, #170 ; 0xaa\n", + " 5ae: 23ac movs r3, #172 ; 0xac\n", + " 5b0: 23ae movs r3, #174 ; 0xae\n", + " 5b2: 23b0 movs r3, #176 ; 0xb0\n", + " 5b4: 23b2 movs r3, #178 ; 0xb2\n", + " 5b6: 23b4 movs r3, #180 ; 0xb4\n", + " 5b8: 23b6 movs r3, #182 ; 0xb6\n", + " 5ba: 23b8 movs r3, #184 ; 0xb8\n", + " 5bc: 23ba movs r3, #186 ; 0xba\n", + " 5be: 23bc movs r3, #188 ; 0xbc\n", + " 5c0: 23be movs r3, #190 ; 0xbe\n", + " 5c2: 23c0 movs r3, #192 ; 0xc0\n", + " 5c4: 23c2 movs r3, #194 ; 0xc2\n", + " 5c6: 23c4 movs r3, #196 ; 0xc4\n", + " 5c8: 23c6 movs r3, #198 ; 0xc6\n", + " 5ca: 23c8 movs r3, #200 ; 0xc8\n", + " 5cc: 23ca movs r3, #202 ; 0xca\n", + " 5ce: 23cc movs r3, #204 ; 0xcc\n", + " 5d0: 23ce movs r3, #206 ; 0xce\n", + " 5d2: 23d0 movs r3, #208 ; 0xd0\n", + " 5d4: 23d2 movs r3, #210 ; 0xd2\n", + " 5d6: 23d4 movs r3, #212 ; 0xd4\n", + " 5d8: 23d6 movs r3, #214 ; 0xd6\n", + " 5da: 23d8 movs r3, #216 ; 0xd8\n", + " 5dc: 23da movs r3, #218 ; 0xda\n", + " 5de: 23dc movs r3, #220 ; 0xdc\n", + " 5e0: 23de movs r3, #222 ; 0xde\n", + " 5e2: 23e0 movs r3, #224 ; 0xe0\n", + " 5e4: 23e2 movs r3, #226 ; 0xe2\n", + " 5e6: 23e4 movs r3, #228 ; 0xe4\n", + " 5e8: 23e6 movs r3, #230 ; 0xe6\n", + " 5ea: 23e8 movs r3, #232 ; 0xe8\n", + " 5ec: 23ea movs r3, #234 ; 0xea\n", + " 5ee: 23ec movs r3, #236 ; 0xec\n", + " 5f0: 23ee movs r3, #238 ; 0xee\n", + " 5f2: 23f0 movs r3, #240 ; 0xf0\n", + " 5f4: 23f2 movs r3, #242 ; 0xf2\n", + " 5f6: 23f4 movs r3, #244 ; 0xf4\n", + " 5f8: 23f6 movs r3, #246 ; 0xf6\n", + " 5fa: 23f8 movs r3, #248 ; 0xf8\n", + " 5fc: 23fa movs r3, #250 ; 0xfa\n", + " 5fe: 23fc movs r3, #252 ; 0xfc\n", + " 600: 23fe movs r3, #254 ; 0xfe\n", + " 602: 2300 movs r3, #0\n", + " 604: 2302 movs r3, #2\n", + " 606: 2304 movs r3, #4\n", + " 608: 2306 movs r3, #6\n", + " 60a: 2308 movs r3, #8\n", + " 60c: 230a movs r3, #10\n", + " 60e: 230c movs r3, #12\n", + " 610: 230e movs r3, #14\n", + " 612: 2310 movs r3, #16\n", + " 614: 2312 movs r3, #18\n", + " 616: 2314 movs r3, #20\n", + " 618: 2316 movs r3, #22\n", + " 61a: 2318 movs r3, #24\n", + " 61c: 231a movs r3, #26\n", + " 61e: 231c movs r3, #28\n", + " 620: 231e movs r3, #30\n", + " 622: 2320 movs r3, #32\n", + " 624: 2322 movs r3, #34 ; 0x22\n", + " 626: 2324 movs r3, #36 ; 0x24\n", + " 628: 2326 movs r3, #38 ; 0x26\n", + " 62a: 2328 movs r3, #40 ; 0x28\n", + " 62c: 232a movs r3, #42 ; 0x2a\n", + " 62e: 232c movs r3, #44 ; 0x2c\n", + " 630: 232e movs r3, #46 ; 0x2e\n", + " 632: 2330 movs r3, #48 ; 0x30\n", + " 634: 2332 movs r3, #50 ; 0x32\n", + " 636: 2334 movs r3, #52 ; 0x34\n", + " 638: 2336 movs r3, #54 ; 0x36\n", + " 63a: 2338 movs r3, #56 ; 0x38\n", + " 63c: 233a movs r3, #58 ; 0x3a\n", + " 63e: 233c movs r3, #60 ; 0x3c\n", + " 640: 233e movs r3, #62 ; 0x3e\n", + " 642: 2340 movs r3, #64 ; 0x40\n", + " 644: 2342 movs r3, #66 ; 0x42\n", + " 646: 2344 movs r3, #68 ; 0x44\n", + " 648: 2346 movs r3, #70 ; 0x46\n", + " 64a: 2348 movs r3, #72 ; 0x48\n", + " 64c: 234a movs r3, #74 ; 0x4a\n", + " 64e: 234c movs r3, #76 ; 0x4c\n", + " 650: 234e movs r3, #78 ; 0x4e\n", + " 652: 2350 movs r3, #80 ; 0x50\n", + " 654: 2352 movs r3, #82 ; 0x52\n", + " 656: 2354 movs r3, #84 ; 0x54\n", + " 658: 2356 movs r3, #86 ; 0x56\n", + " 65a: 2358 movs r3, #88 ; 0x58\n", + " 65c: 235a movs r3, #90 ; 0x5a\n", + " 65e: 235c movs r3, #92 ; 0x5c\n", + " 660: 235e movs r3, #94 ; 0x5e\n", + " 662: 2360 movs r3, #96 ; 0x60\n", + " 664: 2362 movs r3, #98 ; 0x62\n", + " 666: 2364 movs r3, #100 ; 0x64\n", + " 668: 2366 movs r3, #102 ; 0x66\n", + " 66a: 2368 movs r3, #104 ; 0x68\n", + " 66c: 236a movs r3, #106 ; 0x6a\n", + " 66e: 236c movs r3, #108 ; 0x6c\n", + " 670: 236e movs r3, #110 ; 0x6e\n", + " 672: 2370 movs r3, #112 ; 0x70\n", + " 674: 2372 movs r3, #114 ; 0x72\n", + " 676: 2374 movs r3, #116 ; 0x74\n", + " 678: 2376 movs r3, #118 ; 0x76\n", + " 67a: 2378 movs r3, #120 ; 0x78\n", + " 67c: 237a movs r3, #122 ; 0x7a\n", + " 67e: 237c movs r3, #124 ; 0x7c\n", + " 680: 237e movs r3, #126 ; 0x7e\n", + " 682: 2380 movs r3, #128 ; 0x80\n", + " 684: 2382 movs r3, #130 ; 0x82\n", + " 686: 2384 movs r3, #132 ; 0x84\n", + " 688: 2386 movs r3, #134 ; 0x86\n", + " 68a: 2388 movs r3, #136 ; 0x88\n", + " 68c: 238a movs r3, #138 ; 0x8a\n", + " 68e: 238c movs r3, #140 ; 0x8c\n", + " 690: 238e movs r3, #142 ; 0x8e\n", + " 692: 2390 movs r3, #144 ; 0x90\n", + " 694: 2392 movs r3, #146 ; 0x92\n", + " 696: 2394 movs r3, #148 ; 0x94\n", + " 698: 2396 movs r3, #150 ; 0x96\n", + " 69a: 2398 movs r3, #152 ; 0x98\n", + " 69c: 239a movs r3, #154 ; 0x9a\n", + " 69e: 239c movs r3, #156 ; 0x9c\n", + " 6a0: 239e movs r3, #158 ; 0x9e\n", + " 6a2: 23a0 movs r3, #160 ; 0xa0\n", + " 6a4: 23a2 movs r3, #162 ; 0xa2\n", + " 6a6: 23a4 movs r3, #164 ; 0xa4\n", + " 6a8: 23a6 movs r3, #166 ; 0xa6\n", + " 6aa: 23a8 movs r3, #168 ; 0xa8\n", + " 6ac: 23aa movs r3, #170 ; 0xaa\n", + " 6ae: 23ac movs r3, #172 ; 0xac\n", + " 6b0: 23ae movs r3, #174 ; 0xae\n", + " 6b2: 23b0 movs r3, #176 ; 0xb0\n", + " 6b4: 23b2 movs r3, #178 ; 0xb2\n", + " 6b6: 23b4 movs r3, #180 ; 0xb4\n", + " 6b8: 23b6 movs r3, #182 ; 0xb6\n", + " 6ba: 23b8 movs r3, #184 ; 0xb8\n", + " 6bc: 23ba movs r3, #186 ; 0xba\n", + " 6be: 23bc movs r3, #188 ; 0xbc\n", + " 6c0: 23be movs r3, #190 ; 0xbe\n", + " 6c2: 23c0 movs r3, #192 ; 0xc0\n", + " 6c4: 23c2 movs r3, #194 ; 0xc2\n", + " 6c6: 23c4 movs r3, #196 ; 0xc4\n", + " 6c8: 23c6 movs r3, #198 ; 0xc6\n", + " 6ca: 23c8 movs r3, #200 ; 0xc8\n", + " 6cc: 23ca movs r3, #202 ; 0xca\n", + " 6ce: 23cc movs r3, #204 ; 0xcc\n", + " 6d0: 23ce movs r3, #206 ; 0xce\n", + " 6d2: 23d0 movs r3, #208 ; 0xd0\n", + " 6d4: 23d2 movs r3, #210 ; 0xd2\n", + " 6d6: 23d4 movs r3, #212 ; 0xd4\n", + " 6d8: 23d6 movs r3, #214 ; 0xd6\n", + " 6da: 23d8 movs r3, #216 ; 0xd8\n", + " 6dc: 23da movs r3, #218 ; 0xda\n", + " 6de: 23dc movs r3, #220 ; 0xdc\n", + " 6e0: 23de movs r3, #222 ; 0xde\n", + " 6e2: 23e0 movs r3, #224 ; 0xe0\n", + " 6e4: 23e2 movs r3, #226 ; 0xe2\n", + " 6e6: 23e4 movs r3, #228 ; 0xe4\n", + " 6e8: 23e6 movs r3, #230 ; 0xe6\n", + " 6ea: 23e8 movs r3, #232 ; 0xe8\n", + " 6ec: 23ea movs r3, #234 ; 0xea\n", + " 6ee: 23ec movs r3, #236 ; 0xec\n", + " 6f0: 23ee movs r3, #238 ; 0xee\n", + " 6f2: 23f0 movs r3, #240 ; 0xf0\n", + " 6f4: 23f2 movs r3, #242 ; 0xf2\n", + " 6f6: 23f4 movs r3, #244 ; 0xf4\n", + " 6f8: 23f6 movs r3, #246 ; 0xf6\n", + " 6fa: 23f8 movs r3, #248 ; 0xf8\n", + " 6fc: 23fa movs r3, #250 ; 0xfa\n", + " 6fe: 23fc movs r3, #252 ; 0xfc\n", + " 700: 23fe movs r3, #254 ; 0xfe\n", + " 702: 2300 movs r3, #0\n", + " 704: 2302 movs r3, #2\n", + " 706: 2304 movs r3, #4\n", + " 708: 2306 movs r3, #6\n", + " 70a: 2308 movs r3, #8\n", + " 70c: 230a movs r3, #10\n", + " 70e: 230c movs r3, #12\n", + " 710: 230e movs r3, #14\n", + " 712: 2310 movs r3, #16\n", + " 714: 2312 movs r3, #18\n", + " 716: 2314 movs r3, #20\n", + " 718: 2316 movs r3, #22\n", + " 71a: 2318 movs r3, #24\n", + " 71c: 231a movs r3, #26\n", + " 71e: 231c movs r3, #28\n", + " 720: 231e movs r3, #30\n", + " 722: 2320 movs r3, #32\n", + " 724: 2322 movs r3, #34 ; 0x22\n", + " 726: 2324 movs r3, #36 ; 0x24\n", + " 728: 2326 movs r3, #38 ; 0x26\n", + " 72a: 2328 movs r3, #40 ; 0x28\n", + " 72c: 232a movs r3, #42 ; 0x2a\n", + " 72e: 232c movs r3, #44 ; 0x2c\n", + " 730: 232e movs r3, #46 ; 0x2e\n", + " 732: 2330 movs r3, #48 ; 0x30\n", + " 734: 2332 movs r3, #50 ; 0x32\n", + " 736: 2334 movs r3, #52 ; 0x34\n", + " 738: 2336 movs r3, #54 ; 0x36\n", + " 73a: 2338 movs r3, #56 ; 0x38\n", + " 73c: 233a movs r3, #58 ; 0x3a\n", + " 73e: 233c movs r3, #60 ; 0x3c\n", + " 740: 233e movs r3, #62 ; 0x3e\n", + " 742: 2340 movs r3, #64 ; 0x40\n", + " 744: 2342 movs r3, #66 ; 0x42\n", + " 746: 2344 movs r3, #68 ; 0x44\n", + " 748: 2346 movs r3, #70 ; 0x46\n", + " 74a: 2348 movs r3, #72 ; 0x48\n", + " 74c: 234a movs r3, #74 ; 0x4a\n", + " 74e: 234c movs r3, #76 ; 0x4c\n", + " 750: 234e movs r3, #78 ; 0x4e\n", + " 752: 2350 movs r3, #80 ; 0x50\n", + " 754: 2352 movs r3, #82 ; 0x52\n", + " 756: 2354 movs r3, #84 ; 0x54\n", + " 758: 2356 movs r3, #86 ; 0x56\n", + " 75a: 2358 movs r3, #88 ; 0x58\n", + " 75c: 235a movs r3, #90 ; 0x5a\n", + " 75e: 235c movs r3, #92 ; 0x5c\n", + " 760: 235e movs r3, #94 ; 0x5e\n", + " 762: 2360 movs r3, #96 ; 0x60\n", + " 764: 2362 movs r3, #98 ; 0x62\n", + " 766: 2364 movs r3, #100 ; 0x64\n", + " 768: 2366 movs r3, #102 ; 0x66\n", + " 76a: 2368 movs r3, #104 ; 0x68\n", + " 76c: 236a movs r3, #106 ; 0x6a\n", + " 76e: 236c movs r3, #108 ; 0x6c\n", + " 770: 236e movs r3, #110 ; 0x6e\n", + " 772: 2370 movs r3, #112 ; 0x70\n", + " 774: 2372 movs r3, #114 ; 0x72\n", + " 776: 2374 movs r3, #116 ; 0x74\n", + " 778: 2376 movs r3, #118 ; 0x76\n", + " 77a: 2378 movs r3, #120 ; 0x78\n", + " 77c: 237a movs r3, #122 ; 0x7a\n", + " 77e: 237c movs r3, #124 ; 0x7c\n", + " 780: 237e movs r3, #126 ; 0x7e\n", + " 782: 2380 movs r3, #128 ; 0x80\n", + " 784: 2382 movs r3, #130 ; 0x82\n", + " 786: 2384 movs r3, #132 ; 0x84\n", + " 788: 2386 movs r3, #134 ; 0x86\n", + " 78a: 2388 movs r3, #136 ; 0x88\n", + " 78c: 238a movs r3, #138 ; 0x8a\n", + " 78e: 238c movs r3, #140 ; 0x8c\n", + " 790: 238e movs r3, #142 ; 0x8e\n", + " 792: 2390 movs r3, #144 ; 0x90\n", + " 794: 2392 movs r3, #146 ; 0x92\n", + " 796: 2394 movs r3, #148 ; 0x94\n", + " 798: 2396 movs r3, #150 ; 0x96\n", + " 79a: 2398 movs r3, #152 ; 0x98\n", + " 79c: 239a movs r3, #154 ; 0x9a\n", + " 79e: 239c movs r3, #156 ; 0x9c\n", + " 7a0: 239e movs r3, #158 ; 0x9e\n", + " 7a2: 23a0 movs r3, #160 ; 0xa0\n", + " 7a4: 23a2 movs r3, #162 ; 0xa2\n", + " 7a6: 23a4 movs r3, #164 ; 0xa4\n", + " 7a8: 23a6 movs r3, #166 ; 0xa6\n", + " 7aa: 23a8 movs r3, #168 ; 0xa8\n", + " 7ac: 23aa movs r3, #170 ; 0xaa\n", + " 7ae: 23ac movs r3, #172 ; 0xac\n", + " 7b0: 23ae movs r3, #174 ; 0xae\n", + " 7b2: 23b0 movs r3, #176 ; 0xb0\n", + " 7b4: 23b2 movs r3, #178 ; 0xb2\n", + " 7b6: 23b4 movs r3, #180 ; 0xb4\n", + " 7b8: 23b6 movs r3, #182 ; 0xb6\n", + " 7ba: 23b8 movs r3, #184 ; 0xb8\n", + " 7bc: 23ba movs r3, #186 ; 0xba\n", + " 7be: 23bc movs r3, #188 ; 0xbc\n", + " 7c0: 23be movs r3, #190 ; 0xbe\n", + " 7c2: 23c0 movs r3, #192 ; 0xc0\n", + " 7c4: 23c2 movs r3, #194 ; 0xc2\n", + " 7c6: 23c4 movs r3, #196 ; 0xc4\n", + " 7c8: 23c6 movs r3, #198 ; 0xc6\n", + " 7ca: 23c8 movs r3, #200 ; 0xc8\n", + " 7cc: 23ca movs r3, #202 ; 0xca\n", + " 7ce: 23cc movs r3, #204 ; 0xcc\n", + " 7d0: 23ce movs r3, #206 ; 0xce\n", + " 7d2: 23d0 movs r3, #208 ; 0xd0\n", + " 7d4: 23d2 movs r3, #210 ; 0xd2\n", + " 7d6: 23d4 movs r3, #212 ; 0xd4\n", + " 7d8: 23d6 movs r3, #214 ; 0xd6\n", + " 7da: 23d8 movs r3, #216 ; 0xd8\n", + " 7dc: 23da movs r3, #218 ; 0xda\n", + " 7de: 23dc movs r3, #220 ; 0xdc\n", + " 7e0: 23de movs r3, #222 ; 0xde\n", + " 7e2: 23e0 movs r3, #224 ; 0xe0\n", + " 7e4: 23e2 movs r3, #226 ; 0xe2\n", + " 7e6: 23e4 movs r3, #228 ; 0xe4\n", + " 7e8: 23e6 movs r3, #230 ; 0xe6\n", + " 7ea: 23e8 movs r3, #232 ; 0xe8\n", + " 7ec: 23ea movs r3, #234 ; 0xea\n", + " 7ee: 23ec movs r3, #236 ; 0xec\n", + " 7f0: 23ee movs r3, #238 ; 0xee\n", + " 7f2: 23f0 movs r3, #240 ; 0xf0\n", + " 7f4: 23f2 movs r3, #242 ; 0xf2\n", + " 7f6: 23f4 movs r3, #244 ; 0xf4\n", + " 7f8: 23f6 movs r3, #246 ; 0xf6\n", + " 7fa: 23f8 movs r3, #248 ; 0xf8\n", + " 7fc: 23fa movs r3, #250 ; 0xfa\n", + " 7fe: 23fc movs r3, #252 ; 0xfc\n", + " 800: 23fe movs r3, #254 ; 0xfe\n", + " 802: 0011 movs r1, r2\n", + nullptr +}; +const char* Branch32Results[] = { + " 0: f000 bc01 b.w 806 <Branch32+0x806>\n", + " 4: 2300 movs r3, #0\n", + " 6: 2302 movs r3, #2\n", + " 8: 2304 movs r3, #4\n", + " a: 2306 movs r3, #6\n", + " c: 2308 movs r3, #8\n", + " e: 230a movs r3, #10\n", + " 10: 230c movs r3, #12\n", + " 12: 230e movs r3, #14\n", + " 14: 2310 movs r3, #16\n", + " 16: 2312 movs r3, #18\n", + " 18: 2314 movs r3, #20\n", + " 1a: 2316 movs r3, #22\n", + " 1c: 2318 movs r3, #24\n", + " 1e: 231a movs r3, #26\n", + " 20: 231c movs r3, #28\n", + " 22: 231e movs r3, #30\n", + " 24: 2320 movs r3, #32\n", + " 26: 2322 movs r3, #34 ; 0x22\n", + " 28: 2324 movs r3, #36 ; 0x24\n", + " 2a: 2326 movs r3, #38 ; 0x26\n", + " 2c: 2328 movs r3, #40 ; 0x28\n", + " 2e: 232a movs r3, #42 ; 0x2a\n", + " 30: 232c movs r3, #44 ; 0x2c\n", + " 32: 232e movs r3, #46 ; 0x2e\n", + " 34: 2330 movs r3, #48 ; 0x30\n", + " 36: 2332 movs r3, #50 ; 0x32\n", + " 38: 2334 movs r3, #52 ; 0x34\n", + " 3a: 2336 movs r3, #54 ; 0x36\n", + " 3c: 2338 movs r3, #56 ; 0x38\n", + " 3e: 233a movs r3, #58 ; 0x3a\n", + " 40: 233c movs r3, #60 ; 0x3c\n", + " 42: 233e movs r3, #62 ; 0x3e\n", + " 44: 2340 movs r3, #64 ; 0x40\n", + " 46: 2342 movs r3, #66 ; 0x42\n", + " 48: 2344 movs r3, #68 ; 0x44\n", + " 4a: 2346 movs r3, #70 ; 0x46\n", + " 4c: 2348 movs r3, #72 ; 0x48\n", + " 4e: 234a movs r3, #74 ; 0x4a\n", + " 50: 234c movs r3, #76 ; 0x4c\n", + " 52: 234e movs r3, #78 ; 0x4e\n", + " 54: 2350 movs r3, #80 ; 0x50\n", + " 56: 2352 movs r3, #82 ; 0x52\n", + " 58: 2354 movs r3, #84 ; 0x54\n", + " 5a: 2356 movs r3, #86 ; 0x56\n", + " 5c: 2358 movs r3, #88 ; 0x58\n", + " 5e: 235a movs r3, #90 ; 0x5a\n", + " 60: 235c movs r3, #92 ; 0x5c\n", + " 62: 235e movs r3, #94 ; 0x5e\n", + " 64: 2360 movs r3, #96 ; 0x60\n", + " 66: 2362 movs r3, #98 ; 0x62\n", + " 68: 2364 movs r3, #100 ; 0x64\n", + " 6a: 2366 movs r3, #102 ; 0x66\n", + " 6c: 2368 movs r3, #104 ; 0x68\n", + " 6e: 236a movs r3, #106 ; 0x6a\n", + " 70: 236c movs r3, #108 ; 0x6c\n", + " 72: 236e movs r3, #110 ; 0x6e\n", + " 74: 2370 movs r3, #112 ; 0x70\n", + " 76: 2372 movs r3, #114 ; 0x72\n", + " 78: 2374 movs r3, #116 ; 0x74\n", + " 7a: 2376 movs r3, #118 ; 0x76\n", + " 7c: 2378 movs r3, #120 ; 0x78\n", + " 7e: 237a movs r3, #122 ; 0x7a\n", + " 80: 237c movs r3, #124 ; 0x7c\n", + " 82: 237e movs r3, #126 ; 0x7e\n", + " 84: 2380 movs r3, #128 ; 0x80\n", + " 86: 2382 movs r3, #130 ; 0x82\n", + " 88: 2384 movs r3, #132 ; 0x84\n", + " 8a: 2386 movs r3, #134 ; 0x86\n", + " 8c: 2388 movs r3, #136 ; 0x88\n", + " 8e: 238a movs r3, #138 ; 0x8a\n", + " 90: 238c movs r3, #140 ; 0x8c\n", + " 92: 238e movs r3, #142 ; 0x8e\n", + " 94: 2390 movs r3, #144 ; 0x90\n", + " 96: 2392 movs r3, #146 ; 0x92\n", + " 98: 2394 movs r3, #148 ; 0x94\n", + " 9a: 2396 movs r3, #150 ; 0x96\n", + " 9c: 2398 movs r3, #152 ; 0x98\n", + " 9e: 239a movs r3, #154 ; 0x9a\n", + " a0: 239c movs r3, #156 ; 0x9c\n", + " a2: 239e movs r3, #158 ; 0x9e\n", + " a4: 23a0 movs r3, #160 ; 0xa0\n", + " a6: 23a2 movs r3, #162 ; 0xa2\n", + " a8: 23a4 movs r3, #164 ; 0xa4\n", + " aa: 23a6 movs r3, #166 ; 0xa6\n", + " ac: 23a8 movs r3, #168 ; 0xa8\n", + " ae: 23aa movs r3, #170 ; 0xaa\n", + " b0: 23ac movs r3, #172 ; 0xac\n", + " b2: 23ae movs r3, #174 ; 0xae\n", + " b4: 23b0 movs r3, #176 ; 0xb0\n", + " b6: 23b2 movs r3, #178 ; 0xb2\n", + " b8: 23b4 movs r3, #180 ; 0xb4\n", + " ba: 23b6 movs r3, #182 ; 0xb6\n", + " bc: 23b8 movs r3, #184 ; 0xb8\n", + " be: 23ba movs r3, #186 ; 0xba\n", + " c0: 23bc movs r3, #188 ; 0xbc\n", + " c2: 23be movs r3, #190 ; 0xbe\n", + " c4: 23c0 movs r3, #192 ; 0xc0\n", + " c6: 23c2 movs r3, #194 ; 0xc2\n", + " c8: 23c4 movs r3, #196 ; 0xc4\n", + " ca: 23c6 movs r3, #198 ; 0xc6\n", + " cc: 23c8 movs r3, #200 ; 0xc8\n", + " ce: 23ca movs r3, #202 ; 0xca\n", + " d0: 23cc movs r3, #204 ; 0xcc\n", + " d2: 23ce movs r3, #206 ; 0xce\n", + " d4: 23d0 movs r3, #208 ; 0xd0\n", + " d6: 23d2 movs r3, #210 ; 0xd2\n", + " d8: 23d4 movs r3, #212 ; 0xd4\n", + " da: 23d6 movs r3, #214 ; 0xd6\n", + " dc: 23d8 movs r3, #216 ; 0xd8\n", + " de: 23da movs r3, #218 ; 0xda\n", + " e0: 23dc movs r3, #220 ; 0xdc\n", + " e2: 23de movs r3, #222 ; 0xde\n", + " e4: 23e0 movs r3, #224 ; 0xe0\n", + " e6: 23e2 movs r3, #226 ; 0xe2\n", + " e8: 23e4 movs r3, #228 ; 0xe4\n", + " ea: 23e6 movs r3, #230 ; 0xe6\n", + " ec: 23e8 movs r3, #232 ; 0xe8\n", + " ee: 23ea movs r3, #234 ; 0xea\n", + " f0: 23ec movs r3, #236 ; 0xec\n", + " f2: 23ee movs r3, #238 ; 0xee\n", + " f4: 23f0 movs r3, #240 ; 0xf0\n", + " f6: 23f2 movs r3, #242 ; 0xf2\n", + " f8: 23f4 movs r3, #244 ; 0xf4\n", + " fa: 23f6 movs r3, #246 ; 0xf6\n", + " fc: 23f8 movs r3, #248 ; 0xf8\n", + " fe: 23fa movs r3, #250 ; 0xfa\n", + " 100: 23fc movs r3, #252 ; 0xfc\n", + " 102: 23fe movs r3, #254 ; 0xfe\n", + " 104: 2300 movs r3, #0\n", + " 106: 2302 movs r3, #2\n", + " 108: 2304 movs r3, #4\n", + " 10a: 2306 movs r3, #6\n", + " 10c: 2308 movs r3, #8\n", + " 10e: 230a movs r3, #10\n", + " 110: 230c movs r3, #12\n", + " 112: 230e movs r3, #14\n", + " 114: 2310 movs r3, #16\n", + " 116: 2312 movs r3, #18\n", + " 118: 2314 movs r3, #20\n", + " 11a: 2316 movs r3, #22\n", + " 11c: 2318 movs r3, #24\n", + " 11e: 231a movs r3, #26\n", + " 120: 231c movs r3, #28\n", + " 122: 231e movs r3, #30\n", + " 124: 2320 movs r3, #32\n", + " 126: 2322 movs r3, #34 ; 0x22\n", + " 128: 2324 movs r3, #36 ; 0x24\n", + " 12a: 2326 movs r3, #38 ; 0x26\n", + " 12c: 2328 movs r3, #40 ; 0x28\n", + " 12e: 232a movs r3, #42 ; 0x2a\n", + " 130: 232c movs r3, #44 ; 0x2c\n", + " 132: 232e movs r3, #46 ; 0x2e\n", + " 134: 2330 movs r3, #48 ; 0x30\n", + " 136: 2332 movs r3, #50 ; 0x32\n", + " 138: 2334 movs r3, #52 ; 0x34\n", + " 13a: 2336 movs r3, #54 ; 0x36\n", + " 13c: 2338 movs r3, #56 ; 0x38\n", + " 13e: 233a movs r3, #58 ; 0x3a\n", + " 140: 233c movs r3, #60 ; 0x3c\n", + " 142: 233e movs r3, #62 ; 0x3e\n", + " 144: 2340 movs r3, #64 ; 0x40\n", + " 146: 2342 movs r3, #66 ; 0x42\n", + " 148: 2344 movs r3, #68 ; 0x44\n", + " 14a: 2346 movs r3, #70 ; 0x46\n", + " 14c: 2348 movs r3, #72 ; 0x48\n", + " 14e: 234a movs r3, #74 ; 0x4a\n", + " 150: 234c movs r3, #76 ; 0x4c\n", + " 152: 234e movs r3, #78 ; 0x4e\n", + " 154: 2350 movs r3, #80 ; 0x50\n", + " 156: 2352 movs r3, #82 ; 0x52\n", + " 158: 2354 movs r3, #84 ; 0x54\n", + " 15a: 2356 movs r3, #86 ; 0x56\n", + " 15c: 2358 movs r3, #88 ; 0x58\n", + " 15e: 235a movs r3, #90 ; 0x5a\n", + " 160: 235c movs r3, #92 ; 0x5c\n", + " 162: 235e movs r3, #94 ; 0x5e\n", + " 164: 2360 movs r3, #96 ; 0x60\n", + " 166: 2362 movs r3, #98 ; 0x62\n", + " 168: 2364 movs r3, #100 ; 0x64\n", + " 16a: 2366 movs r3, #102 ; 0x66\n", + " 16c: 2368 movs r3, #104 ; 0x68\n", + " 16e: 236a movs r3, #106 ; 0x6a\n", + " 170: 236c movs r3, #108 ; 0x6c\n", + " 172: 236e movs r3, #110 ; 0x6e\n", + " 174: 2370 movs r3, #112 ; 0x70\n", + " 176: 2372 movs r3, #114 ; 0x72\n", + " 178: 2374 movs r3, #116 ; 0x74\n", + " 17a: 2376 movs r3, #118 ; 0x76\n", + " 17c: 2378 movs r3, #120 ; 0x78\n", + " 17e: 237a movs r3, #122 ; 0x7a\n", + " 180: 237c movs r3, #124 ; 0x7c\n", + " 182: 237e movs r3, #126 ; 0x7e\n", + " 184: 2380 movs r3, #128 ; 0x80\n", + " 186: 2382 movs r3, #130 ; 0x82\n", + " 188: 2384 movs r3, #132 ; 0x84\n", + " 18a: 2386 movs r3, #134 ; 0x86\n", + " 18c: 2388 movs r3, #136 ; 0x88\n", + " 18e: 238a movs r3, #138 ; 0x8a\n", + " 190: 238c movs r3, #140 ; 0x8c\n", + " 192: 238e movs r3, #142 ; 0x8e\n", + " 194: 2390 movs r3, #144 ; 0x90\n", + " 196: 2392 movs r3, #146 ; 0x92\n", + " 198: 2394 movs r3, #148 ; 0x94\n", + " 19a: 2396 movs r3, #150 ; 0x96\n", + " 19c: 2398 movs r3, #152 ; 0x98\n", + " 19e: 239a movs r3, #154 ; 0x9a\n", + " 1a0: 239c movs r3, #156 ; 0x9c\n", + " 1a2: 239e movs r3, #158 ; 0x9e\n", + " 1a4: 23a0 movs r3, #160 ; 0xa0\n", + " 1a6: 23a2 movs r3, #162 ; 0xa2\n", + " 1a8: 23a4 movs r3, #164 ; 0xa4\n", + " 1aa: 23a6 movs r3, #166 ; 0xa6\n", + " 1ac: 23a8 movs r3, #168 ; 0xa8\n", + " 1ae: 23aa movs r3, #170 ; 0xaa\n", + " 1b0: 23ac movs r3, #172 ; 0xac\n", + " 1b2: 23ae movs r3, #174 ; 0xae\n", + " 1b4: 23b0 movs r3, #176 ; 0xb0\n", + " 1b6: 23b2 movs r3, #178 ; 0xb2\n", + " 1b8: 23b4 movs r3, #180 ; 0xb4\n", + " 1ba: 23b6 movs r3, #182 ; 0xb6\n", + " 1bc: 23b8 movs r3, #184 ; 0xb8\n", + " 1be: 23ba movs r3, #186 ; 0xba\n", + " 1c0: 23bc movs r3, #188 ; 0xbc\n", + " 1c2: 23be movs r3, #190 ; 0xbe\n", + " 1c4: 23c0 movs r3, #192 ; 0xc0\n", + " 1c6: 23c2 movs r3, #194 ; 0xc2\n", + " 1c8: 23c4 movs r3, #196 ; 0xc4\n", + " 1ca: 23c6 movs r3, #198 ; 0xc6\n", + " 1cc: 23c8 movs r3, #200 ; 0xc8\n", + " 1ce: 23ca movs r3, #202 ; 0xca\n", + " 1d0: 23cc movs r3, #204 ; 0xcc\n", + " 1d2: 23ce movs r3, #206 ; 0xce\n", + " 1d4: 23d0 movs r3, #208 ; 0xd0\n", + " 1d6: 23d2 movs r3, #210 ; 0xd2\n", + " 1d8: 23d4 movs r3, #212 ; 0xd4\n", + " 1da: 23d6 movs r3, #214 ; 0xd6\n", + " 1dc: 23d8 movs r3, #216 ; 0xd8\n", + " 1de: 23da movs r3, #218 ; 0xda\n", + " 1e0: 23dc movs r3, #220 ; 0xdc\n", + " 1e2: 23de movs r3, #222 ; 0xde\n", + " 1e4: 23e0 movs r3, #224 ; 0xe0\n", + " 1e6: 23e2 movs r3, #226 ; 0xe2\n", + " 1e8: 23e4 movs r3, #228 ; 0xe4\n", + " 1ea: 23e6 movs r3, #230 ; 0xe6\n", + " 1ec: 23e8 movs r3, #232 ; 0xe8\n", + " 1ee: 23ea movs r3, #234 ; 0xea\n", + " 1f0: 23ec movs r3, #236 ; 0xec\n", + " 1f2: 23ee movs r3, #238 ; 0xee\n", + " 1f4: 23f0 movs r3, #240 ; 0xf0\n", + " 1f6: 23f2 movs r3, #242 ; 0xf2\n", + " 1f8: 23f4 movs r3, #244 ; 0xf4\n", + " 1fa: 23f6 movs r3, #246 ; 0xf6\n", + " 1fc: 23f8 movs r3, #248 ; 0xf8\n", + " 1fe: 23fa movs r3, #250 ; 0xfa\n", + " 200: 23fc movs r3, #252 ; 0xfc\n", + " 202: 23fe movs r3, #254 ; 0xfe\n", + " 204: 2300 movs r3, #0\n", + " 206: 2302 movs r3, #2\n", + " 208: 2304 movs r3, #4\n", + " 20a: 2306 movs r3, #6\n", + " 20c: 2308 movs r3, #8\n", + " 20e: 230a movs r3, #10\n", + " 210: 230c movs r3, #12\n", + " 212: 230e movs r3, #14\n", + " 214: 2310 movs r3, #16\n", + " 216: 2312 movs r3, #18\n", + " 218: 2314 movs r3, #20\n", + " 21a: 2316 movs r3, #22\n", + " 21c: 2318 movs r3, #24\n", + " 21e: 231a movs r3, #26\n", + " 220: 231c movs r3, #28\n", + " 222: 231e movs r3, #30\n", + " 224: 2320 movs r3, #32\n", + " 226: 2322 movs r3, #34 ; 0x22\n", + " 228: 2324 movs r3, #36 ; 0x24\n", + " 22a: 2326 movs r3, #38 ; 0x26\n", + " 22c: 2328 movs r3, #40 ; 0x28\n", + " 22e: 232a movs r3, #42 ; 0x2a\n", + " 230: 232c movs r3, #44 ; 0x2c\n", + " 232: 232e movs r3, #46 ; 0x2e\n", + " 234: 2330 movs r3, #48 ; 0x30\n", + " 236: 2332 movs r3, #50 ; 0x32\n", + " 238: 2334 movs r3, #52 ; 0x34\n", + " 23a: 2336 movs r3, #54 ; 0x36\n", + " 23c: 2338 movs r3, #56 ; 0x38\n", + " 23e: 233a movs r3, #58 ; 0x3a\n", + " 240: 233c movs r3, #60 ; 0x3c\n", + " 242: 233e movs r3, #62 ; 0x3e\n", + " 244: 2340 movs r3, #64 ; 0x40\n", + " 246: 2342 movs r3, #66 ; 0x42\n", + " 248: 2344 movs r3, #68 ; 0x44\n", + " 24a: 2346 movs r3, #70 ; 0x46\n", + " 24c: 2348 movs r3, #72 ; 0x48\n", + " 24e: 234a movs r3, #74 ; 0x4a\n", + " 250: 234c movs r3, #76 ; 0x4c\n", + " 252: 234e movs r3, #78 ; 0x4e\n", + " 254: 2350 movs r3, #80 ; 0x50\n", + " 256: 2352 movs r3, #82 ; 0x52\n", + " 258: 2354 movs r3, #84 ; 0x54\n", + " 25a: 2356 movs r3, #86 ; 0x56\n", + " 25c: 2358 movs r3, #88 ; 0x58\n", + " 25e: 235a movs r3, #90 ; 0x5a\n", + " 260: 235c movs r3, #92 ; 0x5c\n", + " 262: 235e movs r3, #94 ; 0x5e\n", + " 264: 2360 movs r3, #96 ; 0x60\n", + " 266: 2362 movs r3, #98 ; 0x62\n", + " 268: 2364 movs r3, #100 ; 0x64\n", + " 26a: 2366 movs r3, #102 ; 0x66\n", + " 26c: 2368 movs r3, #104 ; 0x68\n", + " 26e: 236a movs r3, #106 ; 0x6a\n", + " 270: 236c movs r3, #108 ; 0x6c\n", + " 272: 236e movs r3, #110 ; 0x6e\n", + " 274: 2370 movs r3, #112 ; 0x70\n", + " 276: 2372 movs r3, #114 ; 0x72\n", + " 278: 2374 movs r3, #116 ; 0x74\n", + " 27a: 2376 movs r3, #118 ; 0x76\n", + " 27c: 2378 movs r3, #120 ; 0x78\n", + " 27e: 237a movs r3, #122 ; 0x7a\n", + " 280: 237c movs r3, #124 ; 0x7c\n", + " 282: 237e movs r3, #126 ; 0x7e\n", + " 284: 2380 movs r3, #128 ; 0x80\n", + " 286: 2382 movs r3, #130 ; 0x82\n", + " 288: 2384 movs r3, #132 ; 0x84\n", + " 28a: 2386 movs r3, #134 ; 0x86\n", + " 28c: 2388 movs r3, #136 ; 0x88\n", + " 28e: 238a movs r3, #138 ; 0x8a\n", + " 290: 238c movs r3, #140 ; 0x8c\n", + " 292: 238e movs r3, #142 ; 0x8e\n", + " 294: 2390 movs r3, #144 ; 0x90\n", + " 296: 2392 movs r3, #146 ; 0x92\n", + " 298: 2394 movs r3, #148 ; 0x94\n", + " 29a: 2396 movs r3, #150 ; 0x96\n", + " 29c: 2398 movs r3, #152 ; 0x98\n", + " 29e: 239a movs r3, #154 ; 0x9a\n", + " 2a0: 239c movs r3, #156 ; 0x9c\n", + " 2a2: 239e movs r3, #158 ; 0x9e\n", + " 2a4: 23a0 movs r3, #160 ; 0xa0\n", + " 2a6: 23a2 movs r3, #162 ; 0xa2\n", + " 2a8: 23a4 movs r3, #164 ; 0xa4\n", + " 2aa: 23a6 movs r3, #166 ; 0xa6\n", + " 2ac: 23a8 movs r3, #168 ; 0xa8\n", + " 2ae: 23aa movs r3, #170 ; 0xaa\n", + " 2b0: 23ac movs r3, #172 ; 0xac\n", + " 2b2: 23ae movs r3, #174 ; 0xae\n", + " 2b4: 23b0 movs r3, #176 ; 0xb0\n", + " 2b6: 23b2 movs r3, #178 ; 0xb2\n", + " 2b8: 23b4 movs r3, #180 ; 0xb4\n", + " 2ba: 23b6 movs r3, #182 ; 0xb6\n", + " 2bc: 23b8 movs r3, #184 ; 0xb8\n", + " 2be: 23ba movs r3, #186 ; 0xba\n", + " 2c0: 23bc movs r3, #188 ; 0xbc\n", + " 2c2: 23be movs r3, #190 ; 0xbe\n", + " 2c4: 23c0 movs r3, #192 ; 0xc0\n", + " 2c6: 23c2 movs r3, #194 ; 0xc2\n", + " 2c8: 23c4 movs r3, #196 ; 0xc4\n", + " 2ca: 23c6 movs r3, #198 ; 0xc6\n", + " 2cc: 23c8 movs r3, #200 ; 0xc8\n", + " 2ce: 23ca movs r3, #202 ; 0xca\n", + " 2d0: 23cc movs r3, #204 ; 0xcc\n", + " 2d2: 23ce movs r3, #206 ; 0xce\n", + " 2d4: 23d0 movs r3, #208 ; 0xd0\n", + " 2d6: 23d2 movs r3, #210 ; 0xd2\n", + " 2d8: 23d4 movs r3, #212 ; 0xd4\n", + " 2da: 23d6 movs r3, #214 ; 0xd6\n", + " 2dc: 23d8 movs r3, #216 ; 0xd8\n", + " 2de: 23da movs r3, #218 ; 0xda\n", + " 2e0: 23dc movs r3, #220 ; 0xdc\n", + " 2e2: 23de movs r3, #222 ; 0xde\n", + " 2e4: 23e0 movs r3, #224 ; 0xe0\n", + " 2e6: 23e2 movs r3, #226 ; 0xe2\n", + " 2e8: 23e4 movs r3, #228 ; 0xe4\n", + " 2ea: 23e6 movs r3, #230 ; 0xe6\n", + " 2ec: 23e8 movs r3, #232 ; 0xe8\n", + " 2ee: 23ea movs r3, #234 ; 0xea\n", + " 2f0: 23ec movs r3, #236 ; 0xec\n", + " 2f2: 23ee movs r3, #238 ; 0xee\n", + " 2f4: 23f0 movs r3, #240 ; 0xf0\n", + " 2f6: 23f2 movs r3, #242 ; 0xf2\n", + " 2f8: 23f4 movs r3, #244 ; 0xf4\n", + " 2fa: 23f6 movs r3, #246 ; 0xf6\n", + " 2fc: 23f8 movs r3, #248 ; 0xf8\n", + " 2fe: 23fa movs r3, #250 ; 0xfa\n", + " 300: 23fc movs r3, #252 ; 0xfc\n", + " 302: 23fe movs r3, #254 ; 0xfe\n", + " 304: 2300 movs r3, #0\n", + " 306: 2302 movs r3, #2\n", + " 308: 2304 movs r3, #4\n", + " 30a: 2306 movs r3, #6\n", + " 30c: 2308 movs r3, #8\n", + " 30e: 230a movs r3, #10\n", + " 310: 230c movs r3, #12\n", + " 312: 230e movs r3, #14\n", + " 314: 2310 movs r3, #16\n", + " 316: 2312 movs r3, #18\n", + " 318: 2314 movs r3, #20\n", + " 31a: 2316 movs r3, #22\n", + " 31c: 2318 movs r3, #24\n", + " 31e: 231a movs r3, #26\n", + " 320: 231c movs r3, #28\n", + " 322: 231e movs r3, #30\n", + " 324: 2320 movs r3, #32\n", + " 326: 2322 movs r3, #34 ; 0x22\n", + " 328: 2324 movs r3, #36 ; 0x24\n", + " 32a: 2326 movs r3, #38 ; 0x26\n", + " 32c: 2328 movs r3, #40 ; 0x28\n", + " 32e: 232a movs r3, #42 ; 0x2a\n", + " 330: 232c movs r3, #44 ; 0x2c\n", + " 332: 232e movs r3, #46 ; 0x2e\n", + " 334: 2330 movs r3, #48 ; 0x30\n", + " 336: 2332 movs r3, #50 ; 0x32\n", + " 338: 2334 movs r3, #52 ; 0x34\n", + " 33a: 2336 movs r3, #54 ; 0x36\n", + " 33c: 2338 movs r3, #56 ; 0x38\n", + " 33e: 233a movs r3, #58 ; 0x3a\n", + " 340: 233c movs r3, #60 ; 0x3c\n", + " 342: 233e movs r3, #62 ; 0x3e\n", + " 344: 2340 movs r3, #64 ; 0x40\n", + " 346: 2342 movs r3, #66 ; 0x42\n", + " 348: 2344 movs r3, #68 ; 0x44\n", + " 34a: 2346 movs r3, #70 ; 0x46\n", + " 34c: 2348 movs r3, #72 ; 0x48\n", + " 34e: 234a movs r3, #74 ; 0x4a\n", + " 350: 234c movs r3, #76 ; 0x4c\n", + " 352: 234e movs r3, #78 ; 0x4e\n", + " 354: 2350 movs r3, #80 ; 0x50\n", + " 356: 2352 movs r3, #82 ; 0x52\n", + " 358: 2354 movs r3, #84 ; 0x54\n", + " 35a: 2356 movs r3, #86 ; 0x56\n", + " 35c: 2358 movs r3, #88 ; 0x58\n", + " 35e: 235a movs r3, #90 ; 0x5a\n", + " 360: 235c movs r3, #92 ; 0x5c\n", + " 362: 235e movs r3, #94 ; 0x5e\n", + " 364: 2360 movs r3, #96 ; 0x60\n", + " 366: 2362 movs r3, #98 ; 0x62\n", + " 368: 2364 movs r3, #100 ; 0x64\n", + " 36a: 2366 movs r3, #102 ; 0x66\n", + " 36c: 2368 movs r3, #104 ; 0x68\n", + " 36e: 236a movs r3, #106 ; 0x6a\n", + " 370: 236c movs r3, #108 ; 0x6c\n", + " 372: 236e movs r3, #110 ; 0x6e\n", + " 374: 2370 movs r3, #112 ; 0x70\n", + " 376: 2372 movs r3, #114 ; 0x72\n", + " 378: 2374 movs r3, #116 ; 0x74\n", + " 37a: 2376 movs r3, #118 ; 0x76\n", + " 37c: 2378 movs r3, #120 ; 0x78\n", + " 37e: 237a movs r3, #122 ; 0x7a\n", + " 380: 237c movs r3, #124 ; 0x7c\n", + " 382: 237e movs r3, #126 ; 0x7e\n", + " 384: 2380 movs r3, #128 ; 0x80\n", + " 386: 2382 movs r3, #130 ; 0x82\n", + " 388: 2384 movs r3, #132 ; 0x84\n", + " 38a: 2386 movs r3, #134 ; 0x86\n", + " 38c: 2388 movs r3, #136 ; 0x88\n", + " 38e: 238a movs r3, #138 ; 0x8a\n", + " 390: 238c movs r3, #140 ; 0x8c\n", + " 392: 238e movs r3, #142 ; 0x8e\n", + " 394: 2390 movs r3, #144 ; 0x90\n", + " 396: 2392 movs r3, #146 ; 0x92\n", + " 398: 2394 movs r3, #148 ; 0x94\n", + " 39a: 2396 movs r3, #150 ; 0x96\n", + " 39c: 2398 movs r3, #152 ; 0x98\n", + " 39e: 239a movs r3, #154 ; 0x9a\n", + " 3a0: 239c movs r3, #156 ; 0x9c\n", + " 3a2: 239e movs r3, #158 ; 0x9e\n", + " 3a4: 23a0 movs r3, #160 ; 0xa0\n", + " 3a6: 23a2 movs r3, #162 ; 0xa2\n", + " 3a8: 23a4 movs r3, #164 ; 0xa4\n", + " 3aa: 23a6 movs r3, #166 ; 0xa6\n", + " 3ac: 23a8 movs r3, #168 ; 0xa8\n", + " 3ae: 23aa movs r3, #170 ; 0xaa\n", + " 3b0: 23ac movs r3, #172 ; 0xac\n", + " 3b2: 23ae movs r3, #174 ; 0xae\n", + " 3b4: 23b0 movs r3, #176 ; 0xb0\n", + " 3b6: 23b2 movs r3, #178 ; 0xb2\n", + " 3b8: 23b4 movs r3, #180 ; 0xb4\n", + " 3ba: 23b6 movs r3, #182 ; 0xb6\n", + " 3bc: 23b8 movs r3, #184 ; 0xb8\n", + " 3be: 23ba movs r3, #186 ; 0xba\n", + " 3c0: 23bc movs r3, #188 ; 0xbc\n", + " 3c2: 23be movs r3, #190 ; 0xbe\n", + " 3c4: 23c0 movs r3, #192 ; 0xc0\n", + " 3c6: 23c2 movs r3, #194 ; 0xc2\n", + " 3c8: 23c4 movs r3, #196 ; 0xc4\n", + " 3ca: 23c6 movs r3, #198 ; 0xc6\n", + " 3cc: 23c8 movs r3, #200 ; 0xc8\n", + " 3ce: 23ca movs r3, #202 ; 0xca\n", + " 3d0: 23cc movs r3, #204 ; 0xcc\n", + " 3d2: 23ce movs r3, #206 ; 0xce\n", + " 3d4: 23d0 movs r3, #208 ; 0xd0\n", + " 3d6: 23d2 movs r3, #210 ; 0xd2\n", + " 3d8: 23d4 movs r3, #212 ; 0xd4\n", + " 3da: 23d6 movs r3, #214 ; 0xd6\n", + " 3dc: 23d8 movs r3, #216 ; 0xd8\n", + " 3de: 23da movs r3, #218 ; 0xda\n", + " 3e0: 23dc movs r3, #220 ; 0xdc\n", + " 3e2: 23de movs r3, #222 ; 0xde\n", + " 3e4: 23e0 movs r3, #224 ; 0xe0\n", + " 3e6: 23e2 movs r3, #226 ; 0xe2\n", + " 3e8: 23e4 movs r3, #228 ; 0xe4\n", + " 3ea: 23e6 movs r3, #230 ; 0xe6\n", + " 3ec: 23e8 movs r3, #232 ; 0xe8\n", + " 3ee: 23ea movs r3, #234 ; 0xea\n", + " 3f0: 23ec movs r3, #236 ; 0xec\n", + " 3f2: 23ee movs r3, #238 ; 0xee\n", + " 3f4: 23f0 movs r3, #240 ; 0xf0\n", + " 3f6: 23f2 movs r3, #242 ; 0xf2\n", + " 3f8: 23f4 movs r3, #244 ; 0xf4\n", + " 3fa: 23f6 movs r3, #246 ; 0xf6\n", + " 3fc: 23f8 movs r3, #248 ; 0xf8\n", + " 3fe: 23fa movs r3, #250 ; 0xfa\n", + " 400: 23fc movs r3, #252 ; 0xfc\n", + " 402: 23fe movs r3, #254 ; 0xfe\n", + " 404: 2300 movs r3, #0\n", + " 406: 2302 movs r3, #2\n", + " 408: 2304 movs r3, #4\n", + " 40a: 2306 movs r3, #6\n", + " 40c: 2308 movs r3, #8\n", + " 40e: 230a movs r3, #10\n", + " 410: 230c movs r3, #12\n", + " 412: 230e movs r3, #14\n", + " 414: 2310 movs r3, #16\n", + " 416: 2312 movs r3, #18\n", + " 418: 2314 movs r3, #20\n", + " 41a: 2316 movs r3, #22\n", + " 41c: 2318 movs r3, #24\n", + " 41e: 231a movs r3, #26\n", + " 420: 231c movs r3, #28\n", + " 422: 231e movs r3, #30\n", + " 424: 2320 movs r3, #32\n", + " 426: 2322 movs r3, #34 ; 0x22\n", + " 428: 2324 movs r3, #36 ; 0x24\n", + " 42a: 2326 movs r3, #38 ; 0x26\n", + " 42c: 2328 movs r3, #40 ; 0x28\n", + " 42e: 232a movs r3, #42 ; 0x2a\n", + " 430: 232c movs r3, #44 ; 0x2c\n", + " 432: 232e movs r3, #46 ; 0x2e\n", + " 434: 2330 movs r3, #48 ; 0x30\n", + " 436: 2332 movs r3, #50 ; 0x32\n", + " 438: 2334 movs r3, #52 ; 0x34\n", + " 43a: 2336 movs r3, #54 ; 0x36\n", + " 43c: 2338 movs r3, #56 ; 0x38\n", + " 43e: 233a movs r3, #58 ; 0x3a\n", + " 440: 233c movs r3, #60 ; 0x3c\n", + " 442: 233e movs r3, #62 ; 0x3e\n", + " 444: 2340 movs r3, #64 ; 0x40\n", + " 446: 2342 movs r3, #66 ; 0x42\n", + " 448: 2344 movs r3, #68 ; 0x44\n", + " 44a: 2346 movs r3, #70 ; 0x46\n", + " 44c: 2348 movs r3, #72 ; 0x48\n", + " 44e: 234a movs r3, #74 ; 0x4a\n", + " 450: 234c movs r3, #76 ; 0x4c\n", + " 452: 234e movs r3, #78 ; 0x4e\n", + " 454: 2350 movs r3, #80 ; 0x50\n", + " 456: 2352 movs r3, #82 ; 0x52\n", + " 458: 2354 movs r3, #84 ; 0x54\n", + " 45a: 2356 movs r3, #86 ; 0x56\n", + " 45c: 2358 movs r3, #88 ; 0x58\n", + " 45e: 235a movs r3, #90 ; 0x5a\n", + " 460: 235c movs r3, #92 ; 0x5c\n", + " 462: 235e movs r3, #94 ; 0x5e\n", + " 464: 2360 movs r3, #96 ; 0x60\n", + " 466: 2362 movs r3, #98 ; 0x62\n", + " 468: 2364 movs r3, #100 ; 0x64\n", + " 46a: 2366 movs r3, #102 ; 0x66\n", + " 46c: 2368 movs r3, #104 ; 0x68\n", + " 46e: 236a movs r3, #106 ; 0x6a\n", + " 470: 236c movs r3, #108 ; 0x6c\n", + " 472: 236e movs r3, #110 ; 0x6e\n", + " 474: 2370 movs r3, #112 ; 0x70\n", + " 476: 2372 movs r3, #114 ; 0x72\n", + " 478: 2374 movs r3, #116 ; 0x74\n", + " 47a: 2376 movs r3, #118 ; 0x76\n", + " 47c: 2378 movs r3, #120 ; 0x78\n", + " 47e: 237a movs r3, #122 ; 0x7a\n", + " 480: 237c movs r3, #124 ; 0x7c\n", + " 482: 237e movs r3, #126 ; 0x7e\n", + " 484: 2380 movs r3, #128 ; 0x80\n", + " 486: 2382 movs r3, #130 ; 0x82\n", + " 488: 2384 movs r3, #132 ; 0x84\n", + " 48a: 2386 movs r3, #134 ; 0x86\n", + " 48c: 2388 movs r3, #136 ; 0x88\n", + " 48e: 238a movs r3, #138 ; 0x8a\n", + " 490: 238c movs r3, #140 ; 0x8c\n", + " 492: 238e movs r3, #142 ; 0x8e\n", + " 494: 2390 movs r3, #144 ; 0x90\n", + " 496: 2392 movs r3, #146 ; 0x92\n", + " 498: 2394 movs r3, #148 ; 0x94\n", + " 49a: 2396 movs r3, #150 ; 0x96\n", + " 49c: 2398 movs r3, #152 ; 0x98\n", + " 49e: 239a movs r3, #154 ; 0x9a\n", + " 4a0: 239c movs r3, #156 ; 0x9c\n", + " 4a2: 239e movs r3, #158 ; 0x9e\n", + " 4a4: 23a0 movs r3, #160 ; 0xa0\n", + " 4a6: 23a2 movs r3, #162 ; 0xa2\n", + " 4a8: 23a4 movs r3, #164 ; 0xa4\n", + " 4aa: 23a6 movs r3, #166 ; 0xa6\n", + " 4ac: 23a8 movs r3, #168 ; 0xa8\n", + " 4ae: 23aa movs r3, #170 ; 0xaa\n", + " 4b0: 23ac movs r3, #172 ; 0xac\n", + " 4b2: 23ae movs r3, #174 ; 0xae\n", + " 4b4: 23b0 movs r3, #176 ; 0xb0\n", + " 4b6: 23b2 movs r3, #178 ; 0xb2\n", + " 4b8: 23b4 movs r3, #180 ; 0xb4\n", + " 4ba: 23b6 movs r3, #182 ; 0xb6\n", + " 4bc: 23b8 movs r3, #184 ; 0xb8\n", + " 4be: 23ba movs r3, #186 ; 0xba\n", + " 4c0: 23bc movs r3, #188 ; 0xbc\n", + " 4c2: 23be movs r3, #190 ; 0xbe\n", + " 4c4: 23c0 movs r3, #192 ; 0xc0\n", + " 4c6: 23c2 movs r3, #194 ; 0xc2\n", + " 4c8: 23c4 movs r3, #196 ; 0xc4\n", + " 4ca: 23c6 movs r3, #198 ; 0xc6\n", + " 4cc: 23c8 movs r3, #200 ; 0xc8\n", + " 4ce: 23ca movs r3, #202 ; 0xca\n", + " 4d0: 23cc movs r3, #204 ; 0xcc\n", + " 4d2: 23ce movs r3, #206 ; 0xce\n", + " 4d4: 23d0 movs r3, #208 ; 0xd0\n", + " 4d6: 23d2 movs r3, #210 ; 0xd2\n", + " 4d8: 23d4 movs r3, #212 ; 0xd4\n", + " 4da: 23d6 movs r3, #214 ; 0xd6\n", + " 4dc: 23d8 movs r3, #216 ; 0xd8\n", + " 4de: 23da movs r3, #218 ; 0xda\n", + " 4e0: 23dc movs r3, #220 ; 0xdc\n", + " 4e2: 23de movs r3, #222 ; 0xde\n", + " 4e4: 23e0 movs r3, #224 ; 0xe0\n", + " 4e6: 23e2 movs r3, #226 ; 0xe2\n", + " 4e8: 23e4 movs r3, #228 ; 0xe4\n", + " 4ea: 23e6 movs r3, #230 ; 0xe6\n", + " 4ec: 23e8 movs r3, #232 ; 0xe8\n", + " 4ee: 23ea movs r3, #234 ; 0xea\n", + " 4f0: 23ec movs r3, #236 ; 0xec\n", + " 4f2: 23ee movs r3, #238 ; 0xee\n", + " 4f4: 23f0 movs r3, #240 ; 0xf0\n", + " 4f6: 23f2 movs r3, #242 ; 0xf2\n", + " 4f8: 23f4 movs r3, #244 ; 0xf4\n", + " 4fa: 23f6 movs r3, #246 ; 0xf6\n", + " 4fc: 23f8 movs r3, #248 ; 0xf8\n", + " 4fe: 23fa movs r3, #250 ; 0xfa\n", + " 500: 23fc movs r3, #252 ; 0xfc\n", + " 502: 23fe movs r3, #254 ; 0xfe\n", + " 504: 2300 movs r3, #0\n", + " 506: 2302 movs r3, #2\n", + " 508: 2304 movs r3, #4\n", + " 50a: 2306 movs r3, #6\n", + " 50c: 2308 movs r3, #8\n", + " 50e: 230a movs r3, #10\n", + " 510: 230c movs r3, #12\n", + " 512: 230e movs r3, #14\n", + " 514: 2310 movs r3, #16\n", + " 516: 2312 movs r3, #18\n", + " 518: 2314 movs r3, #20\n", + " 51a: 2316 movs r3, #22\n", + " 51c: 2318 movs r3, #24\n", + " 51e: 231a movs r3, #26\n", + " 520: 231c movs r3, #28\n", + " 522: 231e movs r3, #30\n", + " 524: 2320 movs r3, #32\n", + " 526: 2322 movs r3, #34 ; 0x22\n", + " 528: 2324 movs r3, #36 ; 0x24\n", + " 52a: 2326 movs r3, #38 ; 0x26\n", + " 52c: 2328 movs r3, #40 ; 0x28\n", + " 52e: 232a movs r3, #42 ; 0x2a\n", + " 530: 232c movs r3, #44 ; 0x2c\n", + " 532: 232e movs r3, #46 ; 0x2e\n", + " 534: 2330 movs r3, #48 ; 0x30\n", + " 536: 2332 movs r3, #50 ; 0x32\n", + " 538: 2334 movs r3, #52 ; 0x34\n", + " 53a: 2336 movs r3, #54 ; 0x36\n", + " 53c: 2338 movs r3, #56 ; 0x38\n", + " 53e: 233a movs r3, #58 ; 0x3a\n", + " 540: 233c movs r3, #60 ; 0x3c\n", + " 542: 233e movs r3, #62 ; 0x3e\n", + " 544: 2340 movs r3, #64 ; 0x40\n", + " 546: 2342 movs r3, #66 ; 0x42\n", + " 548: 2344 movs r3, #68 ; 0x44\n", + " 54a: 2346 movs r3, #70 ; 0x46\n", + " 54c: 2348 movs r3, #72 ; 0x48\n", + " 54e: 234a movs r3, #74 ; 0x4a\n", + " 550: 234c movs r3, #76 ; 0x4c\n", + " 552: 234e movs r3, #78 ; 0x4e\n", + " 554: 2350 movs r3, #80 ; 0x50\n", + " 556: 2352 movs r3, #82 ; 0x52\n", + " 558: 2354 movs r3, #84 ; 0x54\n", + " 55a: 2356 movs r3, #86 ; 0x56\n", + " 55c: 2358 movs r3, #88 ; 0x58\n", + " 55e: 235a movs r3, #90 ; 0x5a\n", + " 560: 235c movs r3, #92 ; 0x5c\n", + " 562: 235e movs r3, #94 ; 0x5e\n", + " 564: 2360 movs r3, #96 ; 0x60\n", + " 566: 2362 movs r3, #98 ; 0x62\n", + " 568: 2364 movs r3, #100 ; 0x64\n", + " 56a: 2366 movs r3, #102 ; 0x66\n", + " 56c: 2368 movs r3, #104 ; 0x68\n", + " 56e: 236a movs r3, #106 ; 0x6a\n", + " 570: 236c movs r3, #108 ; 0x6c\n", + " 572: 236e movs r3, #110 ; 0x6e\n", + " 574: 2370 movs r3, #112 ; 0x70\n", + " 576: 2372 movs r3, #114 ; 0x72\n", + " 578: 2374 movs r3, #116 ; 0x74\n", + " 57a: 2376 movs r3, #118 ; 0x76\n", + " 57c: 2378 movs r3, #120 ; 0x78\n", + " 57e: 237a movs r3, #122 ; 0x7a\n", + " 580: 237c movs r3, #124 ; 0x7c\n", + " 582: 237e movs r3, #126 ; 0x7e\n", + " 584: 2380 movs r3, #128 ; 0x80\n", + " 586: 2382 movs r3, #130 ; 0x82\n", + " 588: 2384 movs r3, #132 ; 0x84\n", + " 58a: 2386 movs r3, #134 ; 0x86\n", + " 58c: 2388 movs r3, #136 ; 0x88\n", + " 58e: 238a movs r3, #138 ; 0x8a\n", + " 590: 238c movs r3, #140 ; 0x8c\n", + " 592: 238e movs r3, #142 ; 0x8e\n", + " 594: 2390 movs r3, #144 ; 0x90\n", + " 596: 2392 movs r3, #146 ; 0x92\n", + " 598: 2394 movs r3, #148 ; 0x94\n", + " 59a: 2396 movs r3, #150 ; 0x96\n", + " 59c: 2398 movs r3, #152 ; 0x98\n", + " 59e: 239a movs r3, #154 ; 0x9a\n", + " 5a0: 239c movs r3, #156 ; 0x9c\n", + " 5a2: 239e movs r3, #158 ; 0x9e\n", + " 5a4: 23a0 movs r3, #160 ; 0xa0\n", + " 5a6: 23a2 movs r3, #162 ; 0xa2\n", + " 5a8: 23a4 movs r3, #164 ; 0xa4\n", + " 5aa: 23a6 movs r3, #166 ; 0xa6\n", + " 5ac: 23a8 movs r3, #168 ; 0xa8\n", + " 5ae: 23aa movs r3, #170 ; 0xaa\n", + " 5b0: 23ac movs r3, #172 ; 0xac\n", + " 5b2: 23ae movs r3, #174 ; 0xae\n", + " 5b4: 23b0 movs r3, #176 ; 0xb0\n", + " 5b6: 23b2 movs r3, #178 ; 0xb2\n", + " 5b8: 23b4 movs r3, #180 ; 0xb4\n", + " 5ba: 23b6 movs r3, #182 ; 0xb6\n", + " 5bc: 23b8 movs r3, #184 ; 0xb8\n", + " 5be: 23ba movs r3, #186 ; 0xba\n", + " 5c0: 23bc movs r3, #188 ; 0xbc\n", + " 5c2: 23be movs r3, #190 ; 0xbe\n", + " 5c4: 23c0 movs r3, #192 ; 0xc0\n", + " 5c6: 23c2 movs r3, #194 ; 0xc2\n", + " 5c8: 23c4 movs r3, #196 ; 0xc4\n", + " 5ca: 23c6 movs r3, #198 ; 0xc6\n", + " 5cc: 23c8 movs r3, #200 ; 0xc8\n", + " 5ce: 23ca movs r3, #202 ; 0xca\n", + " 5d0: 23cc movs r3, #204 ; 0xcc\n", + " 5d2: 23ce movs r3, #206 ; 0xce\n", + " 5d4: 23d0 movs r3, #208 ; 0xd0\n", + " 5d6: 23d2 movs r3, #210 ; 0xd2\n", + " 5d8: 23d4 movs r3, #212 ; 0xd4\n", + " 5da: 23d6 movs r3, #214 ; 0xd6\n", + " 5dc: 23d8 movs r3, #216 ; 0xd8\n", + " 5de: 23da movs r3, #218 ; 0xda\n", + " 5e0: 23dc movs r3, #220 ; 0xdc\n", + " 5e2: 23de movs r3, #222 ; 0xde\n", + " 5e4: 23e0 movs r3, #224 ; 0xe0\n", + " 5e6: 23e2 movs r3, #226 ; 0xe2\n", + " 5e8: 23e4 movs r3, #228 ; 0xe4\n", + " 5ea: 23e6 movs r3, #230 ; 0xe6\n", + " 5ec: 23e8 movs r3, #232 ; 0xe8\n", + " 5ee: 23ea movs r3, #234 ; 0xea\n", + " 5f0: 23ec movs r3, #236 ; 0xec\n", + " 5f2: 23ee movs r3, #238 ; 0xee\n", + " 5f4: 23f0 movs r3, #240 ; 0xf0\n", + " 5f6: 23f2 movs r3, #242 ; 0xf2\n", + " 5f8: 23f4 movs r3, #244 ; 0xf4\n", + " 5fa: 23f6 movs r3, #246 ; 0xf6\n", + " 5fc: 23f8 movs r3, #248 ; 0xf8\n", + " 5fe: 23fa movs r3, #250 ; 0xfa\n", + " 600: 23fc movs r3, #252 ; 0xfc\n", + " 602: 23fe movs r3, #254 ; 0xfe\n", + " 604: 2300 movs r3, #0\n", + " 606: 2302 movs r3, #2\n", + " 608: 2304 movs r3, #4\n", + " 60a: 2306 movs r3, #6\n", + " 60c: 2308 movs r3, #8\n", + " 60e: 230a movs r3, #10\n", + " 610: 230c movs r3, #12\n", + " 612: 230e movs r3, #14\n", + " 614: 2310 movs r3, #16\n", + " 616: 2312 movs r3, #18\n", + " 618: 2314 movs r3, #20\n", + " 61a: 2316 movs r3, #22\n", + " 61c: 2318 movs r3, #24\n", + " 61e: 231a movs r3, #26\n", + " 620: 231c movs r3, #28\n", + " 622: 231e movs r3, #30\n", + " 624: 2320 movs r3, #32\n", + " 626: 2322 movs r3, #34 ; 0x22\n", + " 628: 2324 movs r3, #36 ; 0x24\n", + " 62a: 2326 movs r3, #38 ; 0x26\n", + " 62c: 2328 movs r3, #40 ; 0x28\n", + " 62e: 232a movs r3, #42 ; 0x2a\n", + " 630: 232c movs r3, #44 ; 0x2c\n", + " 632: 232e movs r3, #46 ; 0x2e\n", + " 634: 2330 movs r3, #48 ; 0x30\n", + " 636: 2332 movs r3, #50 ; 0x32\n", + " 638: 2334 movs r3, #52 ; 0x34\n", + " 63a: 2336 movs r3, #54 ; 0x36\n", + " 63c: 2338 movs r3, #56 ; 0x38\n", + " 63e: 233a movs r3, #58 ; 0x3a\n", + " 640: 233c movs r3, #60 ; 0x3c\n", + " 642: 233e movs r3, #62 ; 0x3e\n", + " 644: 2340 movs r3, #64 ; 0x40\n", + " 646: 2342 movs r3, #66 ; 0x42\n", + " 648: 2344 movs r3, #68 ; 0x44\n", + " 64a: 2346 movs r3, #70 ; 0x46\n", + " 64c: 2348 movs r3, #72 ; 0x48\n", + " 64e: 234a movs r3, #74 ; 0x4a\n", + " 650: 234c movs r3, #76 ; 0x4c\n", + " 652: 234e movs r3, #78 ; 0x4e\n", + " 654: 2350 movs r3, #80 ; 0x50\n", + " 656: 2352 movs r3, #82 ; 0x52\n", + " 658: 2354 movs r3, #84 ; 0x54\n", + " 65a: 2356 movs r3, #86 ; 0x56\n", + " 65c: 2358 movs r3, #88 ; 0x58\n", + " 65e: 235a movs r3, #90 ; 0x5a\n", + " 660: 235c movs r3, #92 ; 0x5c\n", + " 662: 235e movs r3, #94 ; 0x5e\n", + " 664: 2360 movs r3, #96 ; 0x60\n", + " 666: 2362 movs r3, #98 ; 0x62\n", + " 668: 2364 movs r3, #100 ; 0x64\n", + " 66a: 2366 movs r3, #102 ; 0x66\n", + " 66c: 2368 movs r3, #104 ; 0x68\n", + " 66e: 236a movs r3, #106 ; 0x6a\n", + " 670: 236c movs r3, #108 ; 0x6c\n", + " 672: 236e movs r3, #110 ; 0x6e\n", + " 674: 2370 movs r3, #112 ; 0x70\n", + " 676: 2372 movs r3, #114 ; 0x72\n", + " 678: 2374 movs r3, #116 ; 0x74\n", + " 67a: 2376 movs r3, #118 ; 0x76\n", + " 67c: 2378 movs r3, #120 ; 0x78\n", + " 67e: 237a movs r3, #122 ; 0x7a\n", + " 680: 237c movs r3, #124 ; 0x7c\n", + " 682: 237e movs r3, #126 ; 0x7e\n", + " 684: 2380 movs r3, #128 ; 0x80\n", + " 686: 2382 movs r3, #130 ; 0x82\n", + " 688: 2384 movs r3, #132 ; 0x84\n", + " 68a: 2386 movs r3, #134 ; 0x86\n", + " 68c: 2388 movs r3, #136 ; 0x88\n", + " 68e: 238a movs r3, #138 ; 0x8a\n", + " 690: 238c movs r3, #140 ; 0x8c\n", + " 692: 238e movs r3, #142 ; 0x8e\n", + " 694: 2390 movs r3, #144 ; 0x90\n", + " 696: 2392 movs r3, #146 ; 0x92\n", + " 698: 2394 movs r3, #148 ; 0x94\n", + " 69a: 2396 movs r3, #150 ; 0x96\n", + " 69c: 2398 movs r3, #152 ; 0x98\n", + " 69e: 239a movs r3, #154 ; 0x9a\n", + " 6a0: 239c movs r3, #156 ; 0x9c\n", + " 6a2: 239e movs r3, #158 ; 0x9e\n", + " 6a4: 23a0 movs r3, #160 ; 0xa0\n", + " 6a6: 23a2 movs r3, #162 ; 0xa2\n", + " 6a8: 23a4 movs r3, #164 ; 0xa4\n", + " 6aa: 23a6 movs r3, #166 ; 0xa6\n", + " 6ac: 23a8 movs r3, #168 ; 0xa8\n", + " 6ae: 23aa movs r3, #170 ; 0xaa\n", + " 6b0: 23ac movs r3, #172 ; 0xac\n", + " 6b2: 23ae movs r3, #174 ; 0xae\n", + " 6b4: 23b0 movs r3, #176 ; 0xb0\n", + " 6b6: 23b2 movs r3, #178 ; 0xb2\n", + " 6b8: 23b4 movs r3, #180 ; 0xb4\n", + " 6ba: 23b6 movs r3, #182 ; 0xb6\n", + " 6bc: 23b8 movs r3, #184 ; 0xb8\n", + " 6be: 23ba movs r3, #186 ; 0xba\n", + " 6c0: 23bc movs r3, #188 ; 0xbc\n", + " 6c2: 23be movs r3, #190 ; 0xbe\n", + " 6c4: 23c0 movs r3, #192 ; 0xc0\n", + " 6c6: 23c2 movs r3, #194 ; 0xc2\n", + " 6c8: 23c4 movs r3, #196 ; 0xc4\n", + " 6ca: 23c6 movs r3, #198 ; 0xc6\n", + " 6cc: 23c8 movs r3, #200 ; 0xc8\n", + " 6ce: 23ca movs r3, #202 ; 0xca\n", + " 6d0: 23cc movs r3, #204 ; 0xcc\n", + " 6d2: 23ce movs r3, #206 ; 0xce\n", + " 6d4: 23d0 movs r3, #208 ; 0xd0\n", + " 6d6: 23d2 movs r3, #210 ; 0xd2\n", + " 6d8: 23d4 movs r3, #212 ; 0xd4\n", + " 6da: 23d6 movs r3, #214 ; 0xd6\n", + " 6dc: 23d8 movs r3, #216 ; 0xd8\n", + " 6de: 23da movs r3, #218 ; 0xda\n", + " 6e0: 23dc movs r3, #220 ; 0xdc\n", + " 6e2: 23de movs r3, #222 ; 0xde\n", + " 6e4: 23e0 movs r3, #224 ; 0xe0\n", + " 6e6: 23e2 movs r3, #226 ; 0xe2\n", + " 6e8: 23e4 movs r3, #228 ; 0xe4\n", + " 6ea: 23e6 movs r3, #230 ; 0xe6\n", + " 6ec: 23e8 movs r3, #232 ; 0xe8\n", + " 6ee: 23ea movs r3, #234 ; 0xea\n", + " 6f0: 23ec movs r3, #236 ; 0xec\n", + " 6f2: 23ee movs r3, #238 ; 0xee\n", + " 6f4: 23f0 movs r3, #240 ; 0xf0\n", + " 6f6: 23f2 movs r3, #242 ; 0xf2\n", + " 6f8: 23f4 movs r3, #244 ; 0xf4\n", + " 6fa: 23f6 movs r3, #246 ; 0xf6\n", + " 6fc: 23f8 movs r3, #248 ; 0xf8\n", + " 6fe: 23fa movs r3, #250 ; 0xfa\n", + " 700: 23fc movs r3, #252 ; 0xfc\n", + " 702: 23fe movs r3, #254 ; 0xfe\n", + " 704: 2300 movs r3, #0\n", + " 706: 2302 movs r3, #2\n", + " 708: 2304 movs r3, #4\n", + " 70a: 2306 movs r3, #6\n", + " 70c: 2308 movs r3, #8\n", + " 70e: 230a movs r3, #10\n", + " 710: 230c movs r3, #12\n", + " 712: 230e movs r3, #14\n", + " 714: 2310 movs r3, #16\n", + " 716: 2312 movs r3, #18\n", + " 718: 2314 movs r3, #20\n", + " 71a: 2316 movs r3, #22\n", + " 71c: 2318 movs r3, #24\n", + " 71e: 231a movs r3, #26\n", + " 720: 231c movs r3, #28\n", + " 722: 231e movs r3, #30\n", + " 724: 2320 movs r3, #32\n", + " 726: 2322 movs r3, #34 ; 0x22\n", + " 728: 2324 movs r3, #36 ; 0x24\n", + " 72a: 2326 movs r3, #38 ; 0x26\n", + " 72c: 2328 movs r3, #40 ; 0x28\n", + " 72e: 232a movs r3, #42 ; 0x2a\n", + " 730: 232c movs r3, #44 ; 0x2c\n", + " 732: 232e movs r3, #46 ; 0x2e\n", + " 734: 2330 movs r3, #48 ; 0x30\n", + " 736: 2332 movs r3, #50 ; 0x32\n", + " 738: 2334 movs r3, #52 ; 0x34\n", + " 73a: 2336 movs r3, #54 ; 0x36\n", + " 73c: 2338 movs r3, #56 ; 0x38\n", + " 73e: 233a movs r3, #58 ; 0x3a\n", + " 740: 233c movs r3, #60 ; 0x3c\n", + " 742: 233e movs r3, #62 ; 0x3e\n", + " 744: 2340 movs r3, #64 ; 0x40\n", + " 746: 2342 movs r3, #66 ; 0x42\n", + " 748: 2344 movs r3, #68 ; 0x44\n", + " 74a: 2346 movs r3, #70 ; 0x46\n", + " 74c: 2348 movs r3, #72 ; 0x48\n", + " 74e: 234a movs r3, #74 ; 0x4a\n", + " 750: 234c movs r3, #76 ; 0x4c\n", + " 752: 234e movs r3, #78 ; 0x4e\n", + " 754: 2350 movs r3, #80 ; 0x50\n", + " 756: 2352 movs r3, #82 ; 0x52\n", + " 758: 2354 movs r3, #84 ; 0x54\n", + " 75a: 2356 movs r3, #86 ; 0x56\n", + " 75c: 2358 movs r3, #88 ; 0x58\n", + " 75e: 235a movs r3, #90 ; 0x5a\n", + " 760: 235c movs r3, #92 ; 0x5c\n", + " 762: 235e movs r3, #94 ; 0x5e\n", + " 764: 2360 movs r3, #96 ; 0x60\n", + " 766: 2362 movs r3, #98 ; 0x62\n", + " 768: 2364 movs r3, #100 ; 0x64\n", + " 76a: 2366 movs r3, #102 ; 0x66\n", + " 76c: 2368 movs r3, #104 ; 0x68\n", + " 76e: 236a movs r3, #106 ; 0x6a\n", + " 770: 236c movs r3, #108 ; 0x6c\n", + " 772: 236e movs r3, #110 ; 0x6e\n", + " 774: 2370 movs r3, #112 ; 0x70\n", + " 776: 2372 movs r3, #114 ; 0x72\n", + " 778: 2374 movs r3, #116 ; 0x74\n", + " 77a: 2376 movs r3, #118 ; 0x76\n", + " 77c: 2378 movs r3, #120 ; 0x78\n", + " 77e: 237a movs r3, #122 ; 0x7a\n", + " 780: 237c movs r3, #124 ; 0x7c\n", + " 782: 237e movs r3, #126 ; 0x7e\n", + " 784: 2380 movs r3, #128 ; 0x80\n", + " 786: 2382 movs r3, #130 ; 0x82\n", + " 788: 2384 movs r3, #132 ; 0x84\n", + " 78a: 2386 movs r3, #134 ; 0x86\n", + " 78c: 2388 movs r3, #136 ; 0x88\n", + " 78e: 238a movs r3, #138 ; 0x8a\n", + " 790: 238c movs r3, #140 ; 0x8c\n", + " 792: 238e movs r3, #142 ; 0x8e\n", + " 794: 2390 movs r3, #144 ; 0x90\n", + " 796: 2392 movs r3, #146 ; 0x92\n", + " 798: 2394 movs r3, #148 ; 0x94\n", + " 79a: 2396 movs r3, #150 ; 0x96\n", + " 79c: 2398 movs r3, #152 ; 0x98\n", + " 79e: 239a movs r3, #154 ; 0x9a\n", + " 7a0: 239c movs r3, #156 ; 0x9c\n", + " 7a2: 239e movs r3, #158 ; 0x9e\n", + " 7a4: 23a0 movs r3, #160 ; 0xa0\n", + " 7a6: 23a2 movs r3, #162 ; 0xa2\n", + " 7a8: 23a4 movs r3, #164 ; 0xa4\n", + " 7aa: 23a6 movs r3, #166 ; 0xa6\n", + " 7ac: 23a8 movs r3, #168 ; 0xa8\n", + " 7ae: 23aa movs r3, #170 ; 0xaa\n", + " 7b0: 23ac movs r3, #172 ; 0xac\n", + " 7b2: 23ae movs r3, #174 ; 0xae\n", + " 7b4: 23b0 movs r3, #176 ; 0xb0\n", + " 7b6: 23b2 movs r3, #178 ; 0xb2\n", + " 7b8: 23b4 movs r3, #180 ; 0xb4\n", + " 7ba: 23b6 movs r3, #182 ; 0xb6\n", + " 7bc: 23b8 movs r3, #184 ; 0xb8\n", + " 7be: 23ba movs r3, #186 ; 0xba\n", + " 7c0: 23bc movs r3, #188 ; 0xbc\n", + " 7c2: 23be movs r3, #190 ; 0xbe\n", + " 7c4: 23c0 movs r3, #192 ; 0xc0\n", + " 7c6: 23c2 movs r3, #194 ; 0xc2\n", + " 7c8: 23c4 movs r3, #196 ; 0xc4\n", + " 7ca: 23c6 movs r3, #198 ; 0xc6\n", + " 7cc: 23c8 movs r3, #200 ; 0xc8\n", + " 7ce: 23ca movs r3, #202 ; 0xca\n", + " 7d0: 23cc movs r3, #204 ; 0xcc\n", + " 7d2: 23ce movs r3, #206 ; 0xce\n", + " 7d4: 23d0 movs r3, #208 ; 0xd0\n", + " 7d6: 23d2 movs r3, #210 ; 0xd2\n", + " 7d8: 23d4 movs r3, #212 ; 0xd4\n", + " 7da: 23d6 movs r3, #214 ; 0xd6\n", + " 7dc: 23d8 movs r3, #216 ; 0xd8\n", + " 7de: 23da movs r3, #218 ; 0xda\n", + " 7e0: 23dc movs r3, #220 ; 0xdc\n", + " 7e2: 23de movs r3, #222 ; 0xde\n", + " 7e4: 23e0 movs r3, #224 ; 0xe0\n", + " 7e6: 23e2 movs r3, #226 ; 0xe2\n", + " 7e8: 23e4 movs r3, #228 ; 0xe4\n", + " 7ea: 23e6 movs r3, #230 ; 0xe6\n", + " 7ec: 23e8 movs r3, #232 ; 0xe8\n", + " 7ee: 23ea movs r3, #234 ; 0xea\n", + " 7f0: 23ec movs r3, #236 ; 0xec\n", + " 7f2: 23ee movs r3, #238 ; 0xee\n", + " 7f4: 23f0 movs r3, #240 ; 0xf0\n", + " 7f6: 23f2 movs r3, #242 ; 0xf2\n", + " 7f8: 23f4 movs r3, #244 ; 0xf4\n", + " 7fa: 23f6 movs r3, #246 ; 0xf6\n", + " 7fc: 23f8 movs r3, #248 ; 0xf8\n", + " 7fe: 23fa movs r3, #250 ; 0xfa\n", + " 800: 23fc movs r3, #252 ; 0xfc\n", + " 802: 23fe movs r3, #254 ; 0xfe\n", + " 804: 2300 movs r3, #0\n", + " 806: 0011 movs r1, r2\n", + nullptr +}; +const char* CompareAndBranchMaxResults[] = { + " 0: b3fc cbz r4, 82 <CompareAndBranchMax+0x82>\n", + " 2: 2300 movs r3, #0\n", + " 4: 2302 movs r3, #2\n", + " 6: 2304 movs r3, #4\n", + " 8: 2306 movs r3, #6\n", + " a: 2308 movs r3, #8\n", + " c: 230a movs r3, #10\n", + " e: 230c movs r3, #12\n", + " 10: 230e movs r3, #14\n", + " 12: 2310 movs r3, #16\n", + " 14: 2312 movs r3, #18\n", + " 16: 2314 movs r3, #20\n", + " 18: 2316 movs r3, #22\n", + " 1a: 2318 movs r3, #24\n", + " 1c: 231a movs r3, #26\n", + " 1e: 231c movs r3, #28\n", + " 20: 231e movs r3, #30\n", + " 22: 2320 movs r3, #32\n", + " 24: 2322 movs r3, #34 ; 0x22\n", + " 26: 2324 movs r3, #36 ; 0x24\n", + " 28: 2326 movs r3, #38 ; 0x26\n", + " 2a: 2328 movs r3, #40 ; 0x28\n", + " 2c: 232a movs r3, #42 ; 0x2a\n", + " 2e: 232c movs r3, #44 ; 0x2c\n", + " 30: 232e movs r3, #46 ; 0x2e\n", + " 32: 2330 movs r3, #48 ; 0x30\n", + " 34: 2332 movs r3, #50 ; 0x32\n", + " 36: 2334 movs r3, #52 ; 0x34\n", + " 38: 2336 movs r3, #54 ; 0x36\n", + " 3a: 2338 movs r3, #56 ; 0x38\n", + " 3c: 233a movs r3, #58 ; 0x3a\n", + " 3e: 233c movs r3, #60 ; 0x3c\n", + " 40: 233e movs r3, #62 ; 0x3e\n", + " 42: 2340 movs r3, #64 ; 0x40\n", + " 44: 2342 movs r3, #66 ; 0x42\n", + " 46: 2344 movs r3, #68 ; 0x44\n", + " 48: 2346 movs r3, #70 ; 0x46\n", + " 4a: 2348 movs r3, #72 ; 0x48\n", + " 4c: 234a movs r3, #74 ; 0x4a\n", + " 4e: 234c movs r3, #76 ; 0x4c\n", + " 50: 234e movs r3, #78 ; 0x4e\n", + " 52: 2350 movs r3, #80 ; 0x50\n", + " 54: 2352 movs r3, #82 ; 0x52\n", + " 56: 2354 movs r3, #84 ; 0x54\n", + " 58: 2356 movs r3, #86 ; 0x56\n", + " 5a: 2358 movs r3, #88 ; 0x58\n", + " 5c: 235a movs r3, #90 ; 0x5a\n", + " 5e: 235c movs r3, #92 ; 0x5c\n", + " 60: 235e movs r3, #94 ; 0x5e\n", + " 62: 2360 movs r3, #96 ; 0x60\n", + " 64: 2362 movs r3, #98 ; 0x62\n", + " 66: 2364 movs r3, #100 ; 0x64\n", + " 68: 2366 movs r3, #102 ; 0x66\n", + " 6a: 2368 movs r3, #104 ; 0x68\n", + " 6c: 236a movs r3, #106 ; 0x6a\n", + " 6e: 236c movs r3, #108 ; 0x6c\n", + " 70: 236e movs r3, #110 ; 0x6e\n", + " 72: 2370 movs r3, #112 ; 0x70\n", + " 74: 2372 movs r3, #114 ; 0x72\n", + " 76: 2374 movs r3, #116 ; 0x74\n", + " 78: 2376 movs r3, #118 ; 0x76\n", + " 7a: 2378 movs r3, #120 ; 0x78\n", + " 7c: 237a movs r3, #122 ; 0x7a\n", + " 7e: 237c movs r3, #124 ; 0x7c\n", + " 80: 237e movs r3, #126 ; 0x7e\n", + " 82: 0011 movs r1, r2\n", + nullptr +}; +const char* CompareAndBranchRelocation16Results[] = { + " 0: 2c00 cmp r4, #0\n", + " 2: d040 beq.n 86 <CompareAndBranchRelocation16+0x86>\n", + " 4: 2300 movs r3, #0\n", + " 6: 2302 movs r3, #2\n", + " 8: 2304 movs r3, #4\n", + " a: 2306 movs r3, #6\n", + " c: 2308 movs r3, #8\n", + " e: 230a movs r3, #10\n", + " 10: 230c movs r3, #12\n", + " 12: 230e movs r3, #14\n", + " 14: 2310 movs r3, #16\n", + " 16: 2312 movs r3, #18\n", + " 18: 2314 movs r3, #20\n", + " 1a: 2316 movs r3, #22\n", + " 1c: 2318 movs r3, #24\n", + " 1e: 231a movs r3, #26\n", + " 20: 231c movs r3, #28\n", + " 22: 231e movs r3, #30\n", + " 24: 2320 movs r3, #32\n", + " 26: 2322 movs r3, #34 ; 0x22\n", + " 28: 2324 movs r3, #36 ; 0x24\n", + " 2a: 2326 movs r3, #38 ; 0x26\n", + " 2c: 2328 movs r3, #40 ; 0x28\n", + " 2e: 232a movs r3, #42 ; 0x2a\n", + " 30: 232c movs r3, #44 ; 0x2c\n", + " 32: 232e movs r3, #46 ; 0x2e\n", + " 34: 2330 movs r3, #48 ; 0x30\n", + " 36: 2332 movs r3, #50 ; 0x32\n", + " 38: 2334 movs r3, #52 ; 0x34\n", + " 3a: 2336 movs r3, #54 ; 0x36\n", + " 3c: 2338 movs r3, #56 ; 0x38\n", + " 3e: 233a movs r3, #58 ; 0x3a\n", + " 40: 233c movs r3, #60 ; 0x3c\n", + " 42: 233e movs r3, #62 ; 0x3e\n", + " 44: 2340 movs r3, #64 ; 0x40\n", + " 46: 2342 movs r3, #66 ; 0x42\n", + " 48: 2344 movs r3, #68 ; 0x44\n", + " 4a: 2346 movs r3, #70 ; 0x46\n", + " 4c: 2348 movs r3, #72 ; 0x48\n", + " 4e: 234a movs r3, #74 ; 0x4a\n", + " 50: 234c movs r3, #76 ; 0x4c\n", + " 52: 234e movs r3, #78 ; 0x4e\n", + " 54: 2350 movs r3, #80 ; 0x50\n", + " 56: 2352 movs r3, #82 ; 0x52\n", + " 58: 2354 movs r3, #84 ; 0x54\n", + " 5a: 2356 movs r3, #86 ; 0x56\n", + " 5c: 2358 movs r3, #88 ; 0x58\n", + " 5e: 235a movs r3, #90 ; 0x5a\n", + " 60: 235c movs r3, #92 ; 0x5c\n", + " 62: 235e movs r3, #94 ; 0x5e\n", + " 64: 2360 movs r3, #96 ; 0x60\n", + " 66: 2362 movs r3, #98 ; 0x62\n", + " 68: 2364 movs r3, #100 ; 0x64\n", + " 6a: 2366 movs r3, #102 ; 0x66\n", + " 6c: 2368 movs r3, #104 ; 0x68\n", + " 6e: 236a movs r3, #106 ; 0x6a\n", + " 70: 236c movs r3, #108 ; 0x6c\n", + " 72: 236e movs r3, #110 ; 0x6e\n", + " 74: 2370 movs r3, #112 ; 0x70\n", + " 76: 2372 movs r3, #114 ; 0x72\n", + " 78: 2374 movs r3, #116 ; 0x74\n", + " 7a: 2376 movs r3, #118 ; 0x76\n", + " 7c: 2378 movs r3, #120 ; 0x78\n", + " 7e: 237a movs r3, #122 ; 0x7a\n", + " 80: 237c movs r3, #124 ; 0x7c\n", + " 82: 237e movs r3, #126 ; 0x7e\n", + " 84: 2380 movs r3, #128 ; 0x80\n", + " 86: 0011 movs r1, r2\n", + nullptr +}; +const char* CompareAndBranchRelocation32Results[] = { + " 0: 2c00 cmp r4, #0\n", + " 2: f000 8401 beq.w 808 <CompareAndBranchRelocation32+0x808>\n", + " 6: 2300 movs r3, #0\n", + " 8: 2302 movs r3, #2\n", + " a: 2304 movs r3, #4\n", + " c: 2306 movs r3, #6\n", + " e: 2308 movs r3, #8\n", + " 10: 230a movs r3, #10\n", + " 12: 230c movs r3, #12\n", + " 14: 230e movs r3, #14\n", + " 16: 2310 movs r3, #16\n", + " 18: 2312 movs r3, #18\n", + " 1a: 2314 movs r3, #20\n", + " 1c: 2316 movs r3, #22\n", + " 1e: 2318 movs r3, #24\n", + " 20: 231a movs r3, #26\n", + " 22: 231c movs r3, #28\n", + " 24: 231e movs r3, #30\n", + " 26: 2320 movs r3, #32\n", + " 28: 2322 movs r3, #34 ; 0x22\n", + " 2a: 2324 movs r3, #36 ; 0x24\n", + " 2c: 2326 movs r3, #38 ; 0x26\n", + " 2e: 2328 movs r3, #40 ; 0x28\n", + " 30: 232a movs r3, #42 ; 0x2a\n", + " 32: 232c movs r3, #44 ; 0x2c\n", + " 34: 232e movs r3, #46 ; 0x2e\n", + " 36: 2330 movs r3, #48 ; 0x30\n", + " 38: 2332 movs r3, #50 ; 0x32\n", + " 3a: 2334 movs r3, #52 ; 0x34\n", + " 3c: 2336 movs r3, #54 ; 0x36\n", + " 3e: 2338 movs r3, #56 ; 0x38\n", + " 40: 233a movs r3, #58 ; 0x3a\n", + " 42: 233c movs r3, #60 ; 0x3c\n", + " 44: 233e movs r3, #62 ; 0x3e\n", + " 46: 2340 movs r3, #64 ; 0x40\n", + " 48: 2342 movs r3, #66 ; 0x42\n", + " 4a: 2344 movs r3, #68 ; 0x44\n", + " 4c: 2346 movs r3, #70 ; 0x46\n", + " 4e: 2348 movs r3, #72 ; 0x48\n", + " 50: 234a movs r3, #74 ; 0x4a\n", + " 52: 234c movs r3, #76 ; 0x4c\n", + " 54: 234e movs r3, #78 ; 0x4e\n", + " 56: 2350 movs r3, #80 ; 0x50\n", + " 58: 2352 movs r3, #82 ; 0x52\n", + " 5a: 2354 movs r3, #84 ; 0x54\n", + " 5c: 2356 movs r3, #86 ; 0x56\n", + " 5e: 2358 movs r3, #88 ; 0x58\n", + " 60: 235a movs r3, #90 ; 0x5a\n", + " 62: 235c movs r3, #92 ; 0x5c\n", + " 64: 235e movs r3, #94 ; 0x5e\n", + " 66: 2360 movs r3, #96 ; 0x60\n", + " 68: 2362 movs r3, #98 ; 0x62\n", + " 6a: 2364 movs r3, #100 ; 0x64\n", + " 6c: 2366 movs r3, #102 ; 0x66\n", + " 6e: 2368 movs r3, #104 ; 0x68\n", + " 70: 236a movs r3, #106 ; 0x6a\n", + " 72: 236c movs r3, #108 ; 0x6c\n", + " 74: 236e movs r3, #110 ; 0x6e\n", + " 76: 2370 movs r3, #112 ; 0x70\n", + " 78: 2372 movs r3, #114 ; 0x72\n", + " 7a: 2374 movs r3, #116 ; 0x74\n", + " 7c: 2376 movs r3, #118 ; 0x76\n", + " 7e: 2378 movs r3, #120 ; 0x78\n", + " 80: 237a movs r3, #122 ; 0x7a\n", + " 82: 237c movs r3, #124 ; 0x7c\n", + " 84: 237e movs r3, #126 ; 0x7e\n", + " 86: 2380 movs r3, #128 ; 0x80\n", + " 88: 2382 movs r3, #130 ; 0x82\n", + " 8a: 2384 movs r3, #132 ; 0x84\n", + " 8c: 2386 movs r3, #134 ; 0x86\n", + " 8e: 2388 movs r3, #136 ; 0x88\n", + " 90: 238a movs r3, #138 ; 0x8a\n", + " 92: 238c movs r3, #140 ; 0x8c\n", + " 94: 238e movs r3, #142 ; 0x8e\n", + " 96: 2390 movs r3, #144 ; 0x90\n", + " 98: 2392 movs r3, #146 ; 0x92\n", + " 9a: 2394 movs r3, #148 ; 0x94\n", + " 9c: 2396 movs r3, #150 ; 0x96\n", + " 9e: 2398 movs r3, #152 ; 0x98\n", + " a0: 239a movs r3, #154 ; 0x9a\n", + " a2: 239c movs r3, #156 ; 0x9c\n", + " a4: 239e movs r3, #158 ; 0x9e\n", + " a6: 23a0 movs r3, #160 ; 0xa0\n", + " a8: 23a2 movs r3, #162 ; 0xa2\n", + " aa: 23a4 movs r3, #164 ; 0xa4\n", + " ac: 23a6 movs r3, #166 ; 0xa6\n", + " ae: 23a8 movs r3, #168 ; 0xa8\n", + " b0: 23aa movs r3, #170 ; 0xaa\n", + " b2: 23ac movs r3, #172 ; 0xac\n", + " b4: 23ae movs r3, #174 ; 0xae\n", + " b6: 23b0 movs r3, #176 ; 0xb0\n", + " b8: 23b2 movs r3, #178 ; 0xb2\n", + " ba: 23b4 movs r3, #180 ; 0xb4\n", + " bc: 23b6 movs r3, #182 ; 0xb6\n", + " be: 23b8 movs r3, #184 ; 0xb8\n", + " c0: 23ba movs r3, #186 ; 0xba\n", + " c2: 23bc movs r3, #188 ; 0xbc\n", + " c4: 23be movs r3, #190 ; 0xbe\n", + " c6: 23c0 movs r3, #192 ; 0xc0\n", + " c8: 23c2 movs r3, #194 ; 0xc2\n", + " ca: 23c4 movs r3, #196 ; 0xc4\n", + " cc: 23c6 movs r3, #198 ; 0xc6\n", + " ce: 23c8 movs r3, #200 ; 0xc8\n", + " d0: 23ca movs r3, #202 ; 0xca\n", + " d2: 23cc movs r3, #204 ; 0xcc\n", + " d4: 23ce movs r3, #206 ; 0xce\n", + " d6: 23d0 movs r3, #208 ; 0xd0\n", + " d8: 23d2 movs r3, #210 ; 0xd2\n", + " da: 23d4 movs r3, #212 ; 0xd4\n", + " dc: 23d6 movs r3, #214 ; 0xd6\n", + " de: 23d8 movs r3, #216 ; 0xd8\n", + " e0: 23da movs r3, #218 ; 0xda\n", + " e2: 23dc movs r3, #220 ; 0xdc\n", + " e4: 23de movs r3, #222 ; 0xde\n", + " e6: 23e0 movs r3, #224 ; 0xe0\n", + " e8: 23e2 movs r3, #226 ; 0xe2\n", + " ea: 23e4 movs r3, #228 ; 0xe4\n", + " ec: 23e6 movs r3, #230 ; 0xe6\n", + " ee: 23e8 movs r3, #232 ; 0xe8\n", + " f0: 23ea movs r3, #234 ; 0xea\n", + " f2: 23ec movs r3, #236 ; 0xec\n", + " f4: 23ee movs r3, #238 ; 0xee\n", + " f6: 23f0 movs r3, #240 ; 0xf0\n", + " f8: 23f2 movs r3, #242 ; 0xf2\n", + " fa: 23f4 movs r3, #244 ; 0xf4\n", + " fc: 23f6 movs r3, #246 ; 0xf6\n", + " fe: 23f8 movs r3, #248 ; 0xf8\n", + " 100: 23fa movs r3, #250 ; 0xfa\n", + " 102: 23fc movs r3, #252 ; 0xfc\n", + " 104: 23fe movs r3, #254 ; 0xfe\n", + " 106: 2300 movs r3, #0\n", + " 108: 2302 movs r3, #2\n", + " 10a: 2304 movs r3, #4\n", + " 10c: 2306 movs r3, #6\n", + " 10e: 2308 movs r3, #8\n", + " 110: 230a movs r3, #10\n", + " 112: 230c movs r3, #12\n", + " 114: 230e movs r3, #14\n", + " 116: 2310 movs r3, #16\n", + " 118: 2312 movs r3, #18\n", + " 11a: 2314 movs r3, #20\n", + " 11c: 2316 movs r3, #22\n", + " 11e: 2318 movs r3, #24\n", + " 120: 231a movs r3, #26\n", + " 122: 231c movs r3, #28\n", + " 124: 231e movs r3, #30\n", + " 126: 2320 movs r3, #32\n", + " 128: 2322 movs r3, #34 ; 0x22\n", + " 12a: 2324 movs r3, #36 ; 0x24\n", + " 12c: 2326 movs r3, #38 ; 0x26\n", + " 12e: 2328 movs r3, #40 ; 0x28\n", + " 130: 232a movs r3, #42 ; 0x2a\n", + " 132: 232c movs r3, #44 ; 0x2c\n", + " 134: 232e movs r3, #46 ; 0x2e\n", + " 136: 2330 movs r3, #48 ; 0x30\n", + " 138: 2332 movs r3, #50 ; 0x32\n", + " 13a: 2334 movs r3, #52 ; 0x34\n", + " 13c: 2336 movs r3, #54 ; 0x36\n", + " 13e: 2338 movs r3, #56 ; 0x38\n", + " 140: 233a movs r3, #58 ; 0x3a\n", + " 142: 233c movs r3, #60 ; 0x3c\n", + " 144: 233e movs r3, #62 ; 0x3e\n", + " 146: 2340 movs r3, #64 ; 0x40\n", + " 148: 2342 movs r3, #66 ; 0x42\n", + " 14a: 2344 movs r3, #68 ; 0x44\n", + " 14c: 2346 movs r3, #70 ; 0x46\n", + " 14e: 2348 movs r3, #72 ; 0x48\n", + " 150: 234a movs r3, #74 ; 0x4a\n", + " 152: 234c movs r3, #76 ; 0x4c\n", + " 154: 234e movs r3, #78 ; 0x4e\n", + " 156: 2350 movs r3, #80 ; 0x50\n", + " 158: 2352 movs r3, #82 ; 0x52\n", + " 15a: 2354 movs r3, #84 ; 0x54\n", + " 15c: 2356 movs r3, #86 ; 0x56\n", + " 15e: 2358 movs r3, #88 ; 0x58\n", + " 160: 235a movs r3, #90 ; 0x5a\n", + " 162: 235c movs r3, #92 ; 0x5c\n", + " 164: 235e movs r3, #94 ; 0x5e\n", + " 166: 2360 movs r3, #96 ; 0x60\n", + " 168: 2362 movs r3, #98 ; 0x62\n", + " 16a: 2364 movs r3, #100 ; 0x64\n", + " 16c: 2366 movs r3, #102 ; 0x66\n", + " 16e: 2368 movs r3, #104 ; 0x68\n", + " 170: 236a movs r3, #106 ; 0x6a\n", + " 172: 236c movs r3, #108 ; 0x6c\n", + " 174: 236e movs r3, #110 ; 0x6e\n", + " 176: 2370 movs r3, #112 ; 0x70\n", + " 178: 2372 movs r3, #114 ; 0x72\n", + " 17a: 2374 movs r3, #116 ; 0x74\n", + " 17c: 2376 movs r3, #118 ; 0x76\n", + " 17e: 2378 movs r3, #120 ; 0x78\n", + " 180: 237a movs r3, #122 ; 0x7a\n", + " 182: 237c movs r3, #124 ; 0x7c\n", + " 184: 237e movs r3, #126 ; 0x7e\n", + " 186: 2380 movs r3, #128 ; 0x80\n", + " 188: 2382 movs r3, #130 ; 0x82\n", + " 18a: 2384 movs r3, #132 ; 0x84\n", + " 18c: 2386 movs r3, #134 ; 0x86\n", + " 18e: 2388 movs r3, #136 ; 0x88\n", + " 190: 238a movs r3, #138 ; 0x8a\n", + " 192: 238c movs r3, #140 ; 0x8c\n", + " 194: 238e movs r3, #142 ; 0x8e\n", + " 196: 2390 movs r3, #144 ; 0x90\n", + " 198: 2392 movs r3, #146 ; 0x92\n", + " 19a: 2394 movs r3, #148 ; 0x94\n", + " 19c: 2396 movs r3, #150 ; 0x96\n", + " 19e: 2398 movs r3, #152 ; 0x98\n", + " 1a0: 239a movs r3, #154 ; 0x9a\n", + " 1a2: 239c movs r3, #156 ; 0x9c\n", + " 1a4: 239e movs r3, #158 ; 0x9e\n", + " 1a6: 23a0 movs r3, #160 ; 0xa0\n", + " 1a8: 23a2 movs r3, #162 ; 0xa2\n", + " 1aa: 23a4 movs r3, #164 ; 0xa4\n", + " 1ac: 23a6 movs r3, #166 ; 0xa6\n", + " 1ae: 23a8 movs r3, #168 ; 0xa8\n", + " 1b0: 23aa movs r3, #170 ; 0xaa\n", + " 1b2: 23ac movs r3, #172 ; 0xac\n", + " 1b4: 23ae movs r3, #174 ; 0xae\n", + " 1b6: 23b0 movs r3, #176 ; 0xb0\n", + " 1b8: 23b2 movs r3, #178 ; 0xb2\n", + " 1ba: 23b4 movs r3, #180 ; 0xb4\n", + " 1bc: 23b6 movs r3, #182 ; 0xb6\n", + " 1be: 23b8 movs r3, #184 ; 0xb8\n", + " 1c0: 23ba movs r3, #186 ; 0xba\n", + " 1c2: 23bc movs r3, #188 ; 0xbc\n", + " 1c4: 23be movs r3, #190 ; 0xbe\n", + " 1c6: 23c0 movs r3, #192 ; 0xc0\n", + " 1c8: 23c2 movs r3, #194 ; 0xc2\n", + " 1ca: 23c4 movs r3, #196 ; 0xc4\n", + " 1cc: 23c6 movs r3, #198 ; 0xc6\n", + " 1ce: 23c8 movs r3, #200 ; 0xc8\n", + " 1d0: 23ca movs r3, #202 ; 0xca\n", + " 1d2: 23cc movs r3, #204 ; 0xcc\n", + " 1d4: 23ce movs r3, #206 ; 0xce\n", + " 1d6: 23d0 movs r3, #208 ; 0xd0\n", + " 1d8: 23d2 movs r3, #210 ; 0xd2\n", + " 1da: 23d4 movs r3, #212 ; 0xd4\n", + " 1dc: 23d6 movs r3, #214 ; 0xd6\n", + " 1de: 23d8 movs r3, #216 ; 0xd8\n", + " 1e0: 23da movs r3, #218 ; 0xda\n", + " 1e2: 23dc movs r3, #220 ; 0xdc\n", + " 1e4: 23de movs r3, #222 ; 0xde\n", + " 1e6: 23e0 movs r3, #224 ; 0xe0\n", + " 1e8: 23e2 movs r3, #226 ; 0xe2\n", + " 1ea: 23e4 movs r3, #228 ; 0xe4\n", + " 1ec: 23e6 movs r3, #230 ; 0xe6\n", + " 1ee: 23e8 movs r3, #232 ; 0xe8\n", + " 1f0: 23ea movs r3, #234 ; 0xea\n", + " 1f2: 23ec movs r3, #236 ; 0xec\n", + " 1f4: 23ee movs r3, #238 ; 0xee\n", + " 1f6: 23f0 movs r3, #240 ; 0xf0\n", + " 1f8: 23f2 movs r3, #242 ; 0xf2\n", + " 1fa: 23f4 movs r3, #244 ; 0xf4\n", + " 1fc: 23f6 movs r3, #246 ; 0xf6\n", + " 1fe: 23f8 movs r3, #248 ; 0xf8\n", + " 200: 23fa movs r3, #250 ; 0xfa\n", + " 202: 23fc movs r3, #252 ; 0xfc\n", + " 204: 23fe movs r3, #254 ; 0xfe\n", + " 206: 2300 movs r3, #0\n", + " 208: 2302 movs r3, #2\n", + " 20a: 2304 movs r3, #4\n", + " 20c: 2306 movs r3, #6\n", + " 20e: 2308 movs r3, #8\n", + " 210: 230a movs r3, #10\n", + " 212: 230c movs r3, #12\n", + " 214: 230e movs r3, #14\n", + " 216: 2310 movs r3, #16\n", + " 218: 2312 movs r3, #18\n", + " 21a: 2314 movs r3, #20\n", + " 21c: 2316 movs r3, #22\n", + " 21e: 2318 movs r3, #24\n", + " 220: 231a movs r3, #26\n", + " 222: 231c movs r3, #28\n", + " 224: 231e movs r3, #30\n", + " 226: 2320 movs r3, #32\n", + " 228: 2322 movs r3, #34 ; 0x22\n", + " 22a: 2324 movs r3, #36 ; 0x24\n", + " 22c: 2326 movs r3, #38 ; 0x26\n", + " 22e: 2328 movs r3, #40 ; 0x28\n", + " 230: 232a movs r3, #42 ; 0x2a\n", + " 232: 232c movs r3, #44 ; 0x2c\n", + " 234: 232e movs r3, #46 ; 0x2e\n", + " 236: 2330 movs r3, #48 ; 0x30\n", + " 238: 2332 movs r3, #50 ; 0x32\n", + " 23a: 2334 movs r3, #52 ; 0x34\n", + " 23c: 2336 movs r3, #54 ; 0x36\n", + " 23e: 2338 movs r3, #56 ; 0x38\n", + " 240: 233a movs r3, #58 ; 0x3a\n", + " 242: 233c movs r3, #60 ; 0x3c\n", + " 244: 233e movs r3, #62 ; 0x3e\n", + " 246: 2340 movs r3, #64 ; 0x40\n", + " 248: 2342 movs r3, #66 ; 0x42\n", + " 24a: 2344 movs r3, #68 ; 0x44\n", + " 24c: 2346 movs r3, #70 ; 0x46\n", + " 24e: 2348 movs r3, #72 ; 0x48\n", + " 250: 234a movs r3, #74 ; 0x4a\n", + " 252: 234c movs r3, #76 ; 0x4c\n", + " 254: 234e movs r3, #78 ; 0x4e\n", + " 256: 2350 movs r3, #80 ; 0x50\n", + " 258: 2352 movs r3, #82 ; 0x52\n", + " 25a: 2354 movs r3, #84 ; 0x54\n", + " 25c: 2356 movs r3, #86 ; 0x56\n", + " 25e: 2358 movs r3, #88 ; 0x58\n", + " 260: 235a movs r3, #90 ; 0x5a\n", + " 262: 235c movs r3, #92 ; 0x5c\n", + " 264: 235e movs r3, #94 ; 0x5e\n", + " 266: 2360 movs r3, #96 ; 0x60\n", + " 268: 2362 movs r3, #98 ; 0x62\n", + " 26a: 2364 movs r3, #100 ; 0x64\n", + " 26c: 2366 movs r3, #102 ; 0x66\n", + " 26e: 2368 movs r3, #104 ; 0x68\n", + " 270: 236a movs r3, #106 ; 0x6a\n", + " 272: 236c movs r3, #108 ; 0x6c\n", + " 274: 236e movs r3, #110 ; 0x6e\n", + " 276: 2370 movs r3, #112 ; 0x70\n", + " 278: 2372 movs r3, #114 ; 0x72\n", + " 27a: 2374 movs r3, #116 ; 0x74\n", + " 27c: 2376 movs r3, #118 ; 0x76\n", + " 27e: 2378 movs r3, #120 ; 0x78\n", + " 280: 237a movs r3, #122 ; 0x7a\n", + " 282: 237c movs r3, #124 ; 0x7c\n", + " 284: 237e movs r3, #126 ; 0x7e\n", + " 286: 2380 movs r3, #128 ; 0x80\n", + " 288: 2382 movs r3, #130 ; 0x82\n", + " 28a: 2384 movs r3, #132 ; 0x84\n", + " 28c: 2386 movs r3, #134 ; 0x86\n", + " 28e: 2388 movs r3, #136 ; 0x88\n", + " 290: 238a movs r3, #138 ; 0x8a\n", + " 292: 238c movs r3, #140 ; 0x8c\n", + " 294: 238e movs r3, #142 ; 0x8e\n", + " 296: 2390 movs r3, #144 ; 0x90\n", + " 298: 2392 movs r3, #146 ; 0x92\n", + " 29a: 2394 movs r3, #148 ; 0x94\n", + " 29c: 2396 movs r3, #150 ; 0x96\n", + " 29e: 2398 movs r3, #152 ; 0x98\n", + " 2a0: 239a movs r3, #154 ; 0x9a\n", + " 2a2: 239c movs r3, #156 ; 0x9c\n", + " 2a4: 239e movs r3, #158 ; 0x9e\n", + " 2a6: 23a0 movs r3, #160 ; 0xa0\n", + " 2a8: 23a2 movs r3, #162 ; 0xa2\n", + " 2aa: 23a4 movs r3, #164 ; 0xa4\n", + " 2ac: 23a6 movs r3, #166 ; 0xa6\n", + " 2ae: 23a8 movs r3, #168 ; 0xa8\n", + " 2b0: 23aa movs r3, #170 ; 0xaa\n", + " 2b2: 23ac movs r3, #172 ; 0xac\n", + " 2b4: 23ae movs r3, #174 ; 0xae\n", + " 2b6: 23b0 movs r3, #176 ; 0xb0\n", + " 2b8: 23b2 movs r3, #178 ; 0xb2\n", + " 2ba: 23b4 movs r3, #180 ; 0xb4\n", + " 2bc: 23b6 movs r3, #182 ; 0xb6\n", + " 2be: 23b8 movs r3, #184 ; 0xb8\n", + " 2c0: 23ba movs r3, #186 ; 0xba\n", + " 2c2: 23bc movs r3, #188 ; 0xbc\n", + " 2c4: 23be movs r3, #190 ; 0xbe\n", + " 2c6: 23c0 movs r3, #192 ; 0xc0\n", + " 2c8: 23c2 movs r3, #194 ; 0xc2\n", + " 2ca: 23c4 movs r3, #196 ; 0xc4\n", + " 2cc: 23c6 movs r3, #198 ; 0xc6\n", + " 2ce: 23c8 movs r3, #200 ; 0xc8\n", + " 2d0: 23ca movs r3, #202 ; 0xca\n", + " 2d2: 23cc movs r3, #204 ; 0xcc\n", + " 2d4: 23ce movs r3, #206 ; 0xce\n", + " 2d6: 23d0 movs r3, #208 ; 0xd0\n", + " 2d8: 23d2 movs r3, #210 ; 0xd2\n", + " 2da: 23d4 movs r3, #212 ; 0xd4\n", + " 2dc: 23d6 movs r3, #214 ; 0xd6\n", + " 2de: 23d8 movs r3, #216 ; 0xd8\n", + " 2e0: 23da movs r3, #218 ; 0xda\n", + " 2e2: 23dc movs r3, #220 ; 0xdc\n", + " 2e4: 23de movs r3, #222 ; 0xde\n", + " 2e6: 23e0 movs r3, #224 ; 0xe0\n", + " 2e8: 23e2 movs r3, #226 ; 0xe2\n", + " 2ea: 23e4 movs r3, #228 ; 0xe4\n", + " 2ec: 23e6 movs r3, #230 ; 0xe6\n", + " 2ee: 23e8 movs r3, #232 ; 0xe8\n", + " 2f0: 23ea movs r3, #234 ; 0xea\n", + " 2f2: 23ec movs r3, #236 ; 0xec\n", + " 2f4: 23ee movs r3, #238 ; 0xee\n", + " 2f6: 23f0 movs r3, #240 ; 0xf0\n", + " 2f8: 23f2 movs r3, #242 ; 0xf2\n", + " 2fa: 23f4 movs r3, #244 ; 0xf4\n", + " 2fc: 23f6 movs r3, #246 ; 0xf6\n", + " 2fe: 23f8 movs r3, #248 ; 0xf8\n", + " 300: 23fa movs r3, #250 ; 0xfa\n", + " 302: 23fc movs r3, #252 ; 0xfc\n", + " 304: 23fe movs r3, #254 ; 0xfe\n", + " 306: 2300 movs r3, #0\n", + " 308: 2302 movs r3, #2\n", + " 30a: 2304 movs r3, #4\n", + " 30c: 2306 movs r3, #6\n", + " 30e: 2308 movs r3, #8\n", + " 310: 230a movs r3, #10\n", + " 312: 230c movs r3, #12\n", + " 314: 230e movs r3, #14\n", + " 316: 2310 movs r3, #16\n", + " 318: 2312 movs r3, #18\n", + " 31a: 2314 movs r3, #20\n", + " 31c: 2316 movs r3, #22\n", + " 31e: 2318 movs r3, #24\n", + " 320: 231a movs r3, #26\n", + " 322: 231c movs r3, #28\n", + " 324: 231e movs r3, #30\n", + " 326: 2320 movs r3, #32\n", + " 328: 2322 movs r3, #34 ; 0x22\n", + " 32a: 2324 movs r3, #36 ; 0x24\n", + " 32c: 2326 movs r3, #38 ; 0x26\n", + " 32e: 2328 movs r3, #40 ; 0x28\n", + " 330: 232a movs r3, #42 ; 0x2a\n", + " 332: 232c movs r3, #44 ; 0x2c\n", + " 334: 232e movs r3, #46 ; 0x2e\n", + " 336: 2330 movs r3, #48 ; 0x30\n", + " 338: 2332 movs r3, #50 ; 0x32\n", + " 33a: 2334 movs r3, #52 ; 0x34\n", + " 33c: 2336 movs r3, #54 ; 0x36\n", + " 33e: 2338 movs r3, #56 ; 0x38\n", + " 340: 233a movs r3, #58 ; 0x3a\n", + " 342: 233c movs r3, #60 ; 0x3c\n", + " 344: 233e movs r3, #62 ; 0x3e\n", + " 346: 2340 movs r3, #64 ; 0x40\n", + " 348: 2342 movs r3, #66 ; 0x42\n", + " 34a: 2344 movs r3, #68 ; 0x44\n", + " 34c: 2346 movs r3, #70 ; 0x46\n", + " 34e: 2348 movs r3, #72 ; 0x48\n", + " 350: 234a movs r3, #74 ; 0x4a\n", + " 352: 234c movs r3, #76 ; 0x4c\n", + " 354: 234e movs r3, #78 ; 0x4e\n", + " 356: 2350 movs r3, #80 ; 0x50\n", + " 358: 2352 movs r3, #82 ; 0x52\n", + " 35a: 2354 movs r3, #84 ; 0x54\n", + " 35c: 2356 movs r3, #86 ; 0x56\n", + " 35e: 2358 movs r3, #88 ; 0x58\n", + " 360: 235a movs r3, #90 ; 0x5a\n", + " 362: 235c movs r3, #92 ; 0x5c\n", + " 364: 235e movs r3, #94 ; 0x5e\n", + " 366: 2360 movs r3, #96 ; 0x60\n", + " 368: 2362 movs r3, #98 ; 0x62\n", + " 36a: 2364 movs r3, #100 ; 0x64\n", + " 36c: 2366 movs r3, #102 ; 0x66\n", + " 36e: 2368 movs r3, #104 ; 0x68\n", + " 370: 236a movs r3, #106 ; 0x6a\n", + " 372: 236c movs r3, #108 ; 0x6c\n", + " 374: 236e movs r3, #110 ; 0x6e\n", + " 376: 2370 movs r3, #112 ; 0x70\n", + " 378: 2372 movs r3, #114 ; 0x72\n", + " 37a: 2374 movs r3, #116 ; 0x74\n", + " 37c: 2376 movs r3, #118 ; 0x76\n", + " 37e: 2378 movs r3, #120 ; 0x78\n", + " 380: 237a movs r3, #122 ; 0x7a\n", + " 382: 237c movs r3, #124 ; 0x7c\n", + " 384: 237e movs r3, #126 ; 0x7e\n", + " 386: 2380 movs r3, #128 ; 0x80\n", + " 388: 2382 movs r3, #130 ; 0x82\n", + " 38a: 2384 movs r3, #132 ; 0x84\n", + " 38c: 2386 movs r3, #134 ; 0x86\n", + " 38e: 2388 movs r3, #136 ; 0x88\n", + " 390: 238a movs r3, #138 ; 0x8a\n", + " 392: 238c movs r3, #140 ; 0x8c\n", + " 394: 238e movs r3, #142 ; 0x8e\n", + " 396: 2390 movs r3, #144 ; 0x90\n", + " 398: 2392 movs r3, #146 ; 0x92\n", + " 39a: 2394 movs r3, #148 ; 0x94\n", + " 39c: 2396 movs r3, #150 ; 0x96\n", + " 39e: 2398 movs r3, #152 ; 0x98\n", + " 3a0: 239a movs r3, #154 ; 0x9a\n", + " 3a2: 239c movs r3, #156 ; 0x9c\n", + " 3a4: 239e movs r3, #158 ; 0x9e\n", + " 3a6: 23a0 movs r3, #160 ; 0xa0\n", + " 3a8: 23a2 movs r3, #162 ; 0xa2\n", + " 3aa: 23a4 movs r3, #164 ; 0xa4\n", + " 3ac: 23a6 movs r3, #166 ; 0xa6\n", + " 3ae: 23a8 movs r3, #168 ; 0xa8\n", + " 3b0: 23aa movs r3, #170 ; 0xaa\n", + " 3b2: 23ac movs r3, #172 ; 0xac\n", + " 3b4: 23ae movs r3, #174 ; 0xae\n", + " 3b6: 23b0 movs r3, #176 ; 0xb0\n", + " 3b8: 23b2 movs r3, #178 ; 0xb2\n", + " 3ba: 23b4 movs r3, #180 ; 0xb4\n", + " 3bc: 23b6 movs r3, #182 ; 0xb6\n", + " 3be: 23b8 movs r3, #184 ; 0xb8\n", + " 3c0: 23ba movs r3, #186 ; 0xba\n", + " 3c2: 23bc movs r3, #188 ; 0xbc\n", + " 3c4: 23be movs r3, #190 ; 0xbe\n", + " 3c6: 23c0 movs r3, #192 ; 0xc0\n", + " 3c8: 23c2 movs r3, #194 ; 0xc2\n", + " 3ca: 23c4 movs r3, #196 ; 0xc4\n", + " 3cc: 23c6 movs r3, #198 ; 0xc6\n", + " 3ce: 23c8 movs r3, #200 ; 0xc8\n", + " 3d0: 23ca movs r3, #202 ; 0xca\n", + " 3d2: 23cc movs r3, #204 ; 0xcc\n", + " 3d4: 23ce movs r3, #206 ; 0xce\n", + " 3d6: 23d0 movs r3, #208 ; 0xd0\n", + " 3d8: 23d2 movs r3, #210 ; 0xd2\n", + " 3da: 23d4 movs r3, #212 ; 0xd4\n", + " 3dc: 23d6 movs r3, #214 ; 0xd6\n", + " 3de: 23d8 movs r3, #216 ; 0xd8\n", + " 3e0: 23da movs r3, #218 ; 0xda\n", + " 3e2: 23dc movs r3, #220 ; 0xdc\n", + " 3e4: 23de movs r3, #222 ; 0xde\n", + " 3e6: 23e0 movs r3, #224 ; 0xe0\n", + " 3e8: 23e2 movs r3, #226 ; 0xe2\n", + " 3ea: 23e4 movs r3, #228 ; 0xe4\n", + " 3ec: 23e6 movs r3, #230 ; 0xe6\n", + " 3ee: 23e8 movs r3, #232 ; 0xe8\n", + " 3f0: 23ea movs r3, #234 ; 0xea\n", + " 3f2: 23ec movs r3, #236 ; 0xec\n", + " 3f4: 23ee movs r3, #238 ; 0xee\n", + " 3f6: 23f0 movs r3, #240 ; 0xf0\n", + " 3f8: 23f2 movs r3, #242 ; 0xf2\n", + " 3fa: 23f4 movs r3, #244 ; 0xf4\n", + " 3fc: 23f6 movs r3, #246 ; 0xf6\n", + " 3fe: 23f8 movs r3, #248 ; 0xf8\n", + " 400: 23fa movs r3, #250 ; 0xfa\n", + " 402: 23fc movs r3, #252 ; 0xfc\n", + " 404: 23fe movs r3, #254 ; 0xfe\n", + " 406: 2300 movs r3, #0\n", + " 408: 2302 movs r3, #2\n", + " 40a: 2304 movs r3, #4\n", + " 40c: 2306 movs r3, #6\n", + " 40e: 2308 movs r3, #8\n", + " 410: 230a movs r3, #10\n", + " 412: 230c movs r3, #12\n", + " 414: 230e movs r3, #14\n", + " 416: 2310 movs r3, #16\n", + " 418: 2312 movs r3, #18\n", + " 41a: 2314 movs r3, #20\n", + " 41c: 2316 movs r3, #22\n", + " 41e: 2318 movs r3, #24\n", + " 420: 231a movs r3, #26\n", + " 422: 231c movs r3, #28\n", + " 424: 231e movs r3, #30\n", + " 426: 2320 movs r3, #32\n", + " 428: 2322 movs r3, #34 ; 0x22\n", + " 42a: 2324 movs r3, #36 ; 0x24\n", + " 42c: 2326 movs r3, #38 ; 0x26\n", + " 42e: 2328 movs r3, #40 ; 0x28\n", + " 430: 232a movs r3, #42 ; 0x2a\n", + " 432: 232c movs r3, #44 ; 0x2c\n", + " 434: 232e movs r3, #46 ; 0x2e\n", + " 436: 2330 movs r3, #48 ; 0x30\n", + " 438: 2332 movs r3, #50 ; 0x32\n", + " 43a: 2334 movs r3, #52 ; 0x34\n", + " 43c: 2336 movs r3, #54 ; 0x36\n", + " 43e: 2338 movs r3, #56 ; 0x38\n", + " 440: 233a movs r3, #58 ; 0x3a\n", + " 442: 233c movs r3, #60 ; 0x3c\n", + " 444: 233e movs r3, #62 ; 0x3e\n", + " 446: 2340 movs r3, #64 ; 0x40\n", + " 448: 2342 movs r3, #66 ; 0x42\n", + " 44a: 2344 movs r3, #68 ; 0x44\n", + " 44c: 2346 movs r3, #70 ; 0x46\n", + " 44e: 2348 movs r3, #72 ; 0x48\n", + " 450: 234a movs r3, #74 ; 0x4a\n", + " 452: 234c movs r3, #76 ; 0x4c\n", + " 454: 234e movs r3, #78 ; 0x4e\n", + " 456: 2350 movs r3, #80 ; 0x50\n", + " 458: 2352 movs r3, #82 ; 0x52\n", + " 45a: 2354 movs r3, #84 ; 0x54\n", + " 45c: 2356 movs r3, #86 ; 0x56\n", + " 45e: 2358 movs r3, #88 ; 0x58\n", + " 460: 235a movs r3, #90 ; 0x5a\n", + " 462: 235c movs r3, #92 ; 0x5c\n", + " 464: 235e movs r3, #94 ; 0x5e\n", + " 466: 2360 movs r3, #96 ; 0x60\n", + " 468: 2362 movs r3, #98 ; 0x62\n", + " 46a: 2364 movs r3, #100 ; 0x64\n", + " 46c: 2366 movs r3, #102 ; 0x66\n", + " 46e: 2368 movs r3, #104 ; 0x68\n", + " 470: 236a movs r3, #106 ; 0x6a\n", + " 472: 236c movs r3, #108 ; 0x6c\n", + " 474: 236e movs r3, #110 ; 0x6e\n", + " 476: 2370 movs r3, #112 ; 0x70\n", + " 478: 2372 movs r3, #114 ; 0x72\n", + " 47a: 2374 movs r3, #116 ; 0x74\n", + " 47c: 2376 movs r3, #118 ; 0x76\n", + " 47e: 2378 movs r3, #120 ; 0x78\n", + " 480: 237a movs r3, #122 ; 0x7a\n", + " 482: 237c movs r3, #124 ; 0x7c\n", + " 484: 237e movs r3, #126 ; 0x7e\n", + " 486: 2380 movs r3, #128 ; 0x80\n", + " 488: 2382 movs r3, #130 ; 0x82\n", + " 48a: 2384 movs r3, #132 ; 0x84\n", + " 48c: 2386 movs r3, #134 ; 0x86\n", + " 48e: 2388 movs r3, #136 ; 0x88\n", + " 490: 238a movs r3, #138 ; 0x8a\n", + " 492: 238c movs r3, #140 ; 0x8c\n", + " 494: 238e movs r3, #142 ; 0x8e\n", + " 496: 2390 movs r3, #144 ; 0x90\n", + " 498: 2392 movs r3, #146 ; 0x92\n", + " 49a: 2394 movs r3, #148 ; 0x94\n", + " 49c: 2396 movs r3, #150 ; 0x96\n", + " 49e: 2398 movs r3, #152 ; 0x98\n", + " 4a0: 239a movs r3, #154 ; 0x9a\n", + " 4a2: 239c movs r3, #156 ; 0x9c\n", + " 4a4: 239e movs r3, #158 ; 0x9e\n", + " 4a6: 23a0 movs r3, #160 ; 0xa0\n", + " 4a8: 23a2 movs r3, #162 ; 0xa2\n", + " 4aa: 23a4 movs r3, #164 ; 0xa4\n", + " 4ac: 23a6 movs r3, #166 ; 0xa6\n", + " 4ae: 23a8 movs r3, #168 ; 0xa8\n", + " 4b0: 23aa movs r3, #170 ; 0xaa\n", + " 4b2: 23ac movs r3, #172 ; 0xac\n", + " 4b4: 23ae movs r3, #174 ; 0xae\n", + " 4b6: 23b0 movs r3, #176 ; 0xb0\n", + " 4b8: 23b2 movs r3, #178 ; 0xb2\n", + " 4ba: 23b4 movs r3, #180 ; 0xb4\n", + " 4bc: 23b6 movs r3, #182 ; 0xb6\n", + " 4be: 23b8 movs r3, #184 ; 0xb8\n", + " 4c0: 23ba movs r3, #186 ; 0xba\n", + " 4c2: 23bc movs r3, #188 ; 0xbc\n", + " 4c4: 23be movs r3, #190 ; 0xbe\n", + " 4c6: 23c0 movs r3, #192 ; 0xc0\n", + " 4c8: 23c2 movs r3, #194 ; 0xc2\n", + " 4ca: 23c4 movs r3, #196 ; 0xc4\n", + " 4cc: 23c6 movs r3, #198 ; 0xc6\n", + " 4ce: 23c8 movs r3, #200 ; 0xc8\n", + " 4d0: 23ca movs r3, #202 ; 0xca\n", + " 4d2: 23cc movs r3, #204 ; 0xcc\n", + " 4d4: 23ce movs r3, #206 ; 0xce\n", + " 4d6: 23d0 movs r3, #208 ; 0xd0\n", + " 4d8: 23d2 movs r3, #210 ; 0xd2\n", + " 4da: 23d4 movs r3, #212 ; 0xd4\n", + " 4dc: 23d6 movs r3, #214 ; 0xd6\n", + " 4de: 23d8 movs r3, #216 ; 0xd8\n", + " 4e0: 23da movs r3, #218 ; 0xda\n", + " 4e2: 23dc movs r3, #220 ; 0xdc\n", + " 4e4: 23de movs r3, #222 ; 0xde\n", + " 4e6: 23e0 movs r3, #224 ; 0xe0\n", + " 4e8: 23e2 movs r3, #226 ; 0xe2\n", + " 4ea: 23e4 movs r3, #228 ; 0xe4\n", + " 4ec: 23e6 movs r3, #230 ; 0xe6\n", + " 4ee: 23e8 movs r3, #232 ; 0xe8\n", + " 4f0: 23ea movs r3, #234 ; 0xea\n", + " 4f2: 23ec movs r3, #236 ; 0xec\n", + " 4f4: 23ee movs r3, #238 ; 0xee\n", + " 4f6: 23f0 movs r3, #240 ; 0xf0\n", + " 4f8: 23f2 movs r3, #242 ; 0xf2\n", + " 4fa: 23f4 movs r3, #244 ; 0xf4\n", + " 4fc: 23f6 movs r3, #246 ; 0xf6\n", + " 4fe: 23f8 movs r3, #248 ; 0xf8\n", + " 500: 23fa movs r3, #250 ; 0xfa\n", + " 502: 23fc movs r3, #252 ; 0xfc\n", + " 504: 23fe movs r3, #254 ; 0xfe\n", + " 506: 2300 movs r3, #0\n", + " 508: 2302 movs r3, #2\n", + " 50a: 2304 movs r3, #4\n", + " 50c: 2306 movs r3, #6\n", + " 50e: 2308 movs r3, #8\n", + " 510: 230a movs r3, #10\n", + " 512: 230c movs r3, #12\n", + " 514: 230e movs r3, #14\n", + " 516: 2310 movs r3, #16\n", + " 518: 2312 movs r3, #18\n", + " 51a: 2314 movs r3, #20\n", + " 51c: 2316 movs r3, #22\n", + " 51e: 2318 movs r3, #24\n", + " 520: 231a movs r3, #26\n", + " 522: 231c movs r3, #28\n", + " 524: 231e movs r3, #30\n", + " 526: 2320 movs r3, #32\n", + " 528: 2322 movs r3, #34 ; 0x22\n", + " 52a: 2324 movs r3, #36 ; 0x24\n", + " 52c: 2326 movs r3, #38 ; 0x26\n", + " 52e: 2328 movs r3, #40 ; 0x28\n", + " 530: 232a movs r3, #42 ; 0x2a\n", + " 532: 232c movs r3, #44 ; 0x2c\n", + " 534: 232e movs r3, #46 ; 0x2e\n", + " 536: 2330 movs r3, #48 ; 0x30\n", + " 538: 2332 movs r3, #50 ; 0x32\n", + " 53a: 2334 movs r3, #52 ; 0x34\n", + " 53c: 2336 movs r3, #54 ; 0x36\n", + " 53e: 2338 movs r3, #56 ; 0x38\n", + " 540: 233a movs r3, #58 ; 0x3a\n", + " 542: 233c movs r3, #60 ; 0x3c\n", + " 544: 233e movs r3, #62 ; 0x3e\n", + " 546: 2340 movs r3, #64 ; 0x40\n", + " 548: 2342 movs r3, #66 ; 0x42\n", + " 54a: 2344 movs r3, #68 ; 0x44\n", + " 54c: 2346 movs r3, #70 ; 0x46\n", + " 54e: 2348 movs r3, #72 ; 0x48\n", + " 550: 234a movs r3, #74 ; 0x4a\n", + " 552: 234c movs r3, #76 ; 0x4c\n", + " 554: 234e movs r3, #78 ; 0x4e\n", + " 556: 2350 movs r3, #80 ; 0x50\n", + " 558: 2352 movs r3, #82 ; 0x52\n", + " 55a: 2354 movs r3, #84 ; 0x54\n", + " 55c: 2356 movs r3, #86 ; 0x56\n", + " 55e: 2358 movs r3, #88 ; 0x58\n", + " 560: 235a movs r3, #90 ; 0x5a\n", + " 562: 235c movs r3, #92 ; 0x5c\n", + " 564: 235e movs r3, #94 ; 0x5e\n", + " 566: 2360 movs r3, #96 ; 0x60\n", + " 568: 2362 movs r3, #98 ; 0x62\n", + " 56a: 2364 movs r3, #100 ; 0x64\n", + " 56c: 2366 movs r3, #102 ; 0x66\n", + " 56e: 2368 movs r3, #104 ; 0x68\n", + " 570: 236a movs r3, #106 ; 0x6a\n", + " 572: 236c movs r3, #108 ; 0x6c\n", + " 574: 236e movs r3, #110 ; 0x6e\n", + " 576: 2370 movs r3, #112 ; 0x70\n", + " 578: 2372 movs r3, #114 ; 0x72\n", + " 57a: 2374 movs r3, #116 ; 0x74\n", + " 57c: 2376 movs r3, #118 ; 0x76\n", + " 57e: 2378 movs r3, #120 ; 0x78\n", + " 580: 237a movs r3, #122 ; 0x7a\n", + " 582: 237c movs r3, #124 ; 0x7c\n", + " 584: 237e movs r3, #126 ; 0x7e\n", + " 586: 2380 movs r3, #128 ; 0x80\n", + " 588: 2382 movs r3, #130 ; 0x82\n", + " 58a: 2384 movs r3, #132 ; 0x84\n", + " 58c: 2386 movs r3, #134 ; 0x86\n", + " 58e: 2388 movs r3, #136 ; 0x88\n", + " 590: 238a movs r3, #138 ; 0x8a\n", + " 592: 238c movs r3, #140 ; 0x8c\n", + " 594: 238e movs r3, #142 ; 0x8e\n", + " 596: 2390 movs r3, #144 ; 0x90\n", + " 598: 2392 movs r3, #146 ; 0x92\n", + " 59a: 2394 movs r3, #148 ; 0x94\n", + " 59c: 2396 movs r3, #150 ; 0x96\n", + " 59e: 2398 movs r3, #152 ; 0x98\n", + " 5a0: 239a movs r3, #154 ; 0x9a\n", + " 5a2: 239c movs r3, #156 ; 0x9c\n", + " 5a4: 239e movs r3, #158 ; 0x9e\n", + " 5a6: 23a0 movs r3, #160 ; 0xa0\n", + " 5a8: 23a2 movs r3, #162 ; 0xa2\n", + " 5aa: 23a4 movs r3, #164 ; 0xa4\n", + " 5ac: 23a6 movs r3, #166 ; 0xa6\n", + " 5ae: 23a8 movs r3, #168 ; 0xa8\n", + " 5b0: 23aa movs r3, #170 ; 0xaa\n", + " 5b2: 23ac movs r3, #172 ; 0xac\n", + " 5b4: 23ae movs r3, #174 ; 0xae\n", + " 5b6: 23b0 movs r3, #176 ; 0xb0\n", + " 5b8: 23b2 movs r3, #178 ; 0xb2\n", + " 5ba: 23b4 movs r3, #180 ; 0xb4\n", + " 5bc: 23b6 movs r3, #182 ; 0xb6\n", + " 5be: 23b8 movs r3, #184 ; 0xb8\n", + " 5c0: 23ba movs r3, #186 ; 0xba\n", + " 5c2: 23bc movs r3, #188 ; 0xbc\n", + " 5c4: 23be movs r3, #190 ; 0xbe\n", + " 5c6: 23c0 movs r3, #192 ; 0xc0\n", + " 5c8: 23c2 movs r3, #194 ; 0xc2\n", + " 5ca: 23c4 movs r3, #196 ; 0xc4\n", + " 5cc: 23c6 movs r3, #198 ; 0xc6\n", + " 5ce: 23c8 movs r3, #200 ; 0xc8\n", + " 5d0: 23ca movs r3, #202 ; 0xca\n", + " 5d2: 23cc movs r3, #204 ; 0xcc\n", + " 5d4: 23ce movs r3, #206 ; 0xce\n", + " 5d6: 23d0 movs r3, #208 ; 0xd0\n", + " 5d8: 23d2 movs r3, #210 ; 0xd2\n", + " 5da: 23d4 movs r3, #212 ; 0xd4\n", + " 5dc: 23d6 movs r3, #214 ; 0xd6\n", + " 5de: 23d8 movs r3, #216 ; 0xd8\n", + " 5e0: 23da movs r3, #218 ; 0xda\n", + " 5e2: 23dc movs r3, #220 ; 0xdc\n", + " 5e4: 23de movs r3, #222 ; 0xde\n", + " 5e6: 23e0 movs r3, #224 ; 0xe0\n", + " 5e8: 23e2 movs r3, #226 ; 0xe2\n", + " 5ea: 23e4 movs r3, #228 ; 0xe4\n", + " 5ec: 23e6 movs r3, #230 ; 0xe6\n", + " 5ee: 23e8 movs r3, #232 ; 0xe8\n", + " 5f0: 23ea movs r3, #234 ; 0xea\n", + " 5f2: 23ec movs r3, #236 ; 0xec\n", + " 5f4: 23ee movs r3, #238 ; 0xee\n", + " 5f6: 23f0 movs r3, #240 ; 0xf0\n", + " 5f8: 23f2 movs r3, #242 ; 0xf2\n", + " 5fa: 23f4 movs r3, #244 ; 0xf4\n", + " 5fc: 23f6 movs r3, #246 ; 0xf6\n", + " 5fe: 23f8 movs r3, #248 ; 0xf8\n", + " 600: 23fa movs r3, #250 ; 0xfa\n", + " 602: 23fc movs r3, #252 ; 0xfc\n", + " 604: 23fe movs r3, #254 ; 0xfe\n", + " 606: 2300 movs r3, #0\n", + " 608: 2302 movs r3, #2\n", + " 60a: 2304 movs r3, #4\n", + " 60c: 2306 movs r3, #6\n", + " 60e: 2308 movs r3, #8\n", + " 610: 230a movs r3, #10\n", + " 612: 230c movs r3, #12\n", + " 614: 230e movs r3, #14\n", + " 616: 2310 movs r3, #16\n", + " 618: 2312 movs r3, #18\n", + " 61a: 2314 movs r3, #20\n", + " 61c: 2316 movs r3, #22\n", + " 61e: 2318 movs r3, #24\n", + " 620: 231a movs r3, #26\n", + " 622: 231c movs r3, #28\n", + " 624: 231e movs r3, #30\n", + " 626: 2320 movs r3, #32\n", + " 628: 2322 movs r3, #34 ; 0x22\n", + " 62a: 2324 movs r3, #36 ; 0x24\n", + " 62c: 2326 movs r3, #38 ; 0x26\n", + " 62e: 2328 movs r3, #40 ; 0x28\n", + " 630: 232a movs r3, #42 ; 0x2a\n", + " 632: 232c movs r3, #44 ; 0x2c\n", + " 634: 232e movs r3, #46 ; 0x2e\n", + " 636: 2330 movs r3, #48 ; 0x30\n", + " 638: 2332 movs r3, #50 ; 0x32\n", + " 63a: 2334 movs r3, #52 ; 0x34\n", + " 63c: 2336 movs r3, #54 ; 0x36\n", + " 63e: 2338 movs r3, #56 ; 0x38\n", + " 640: 233a movs r3, #58 ; 0x3a\n", + " 642: 233c movs r3, #60 ; 0x3c\n", + " 644: 233e movs r3, #62 ; 0x3e\n", + " 646: 2340 movs r3, #64 ; 0x40\n", + " 648: 2342 movs r3, #66 ; 0x42\n", + " 64a: 2344 movs r3, #68 ; 0x44\n", + " 64c: 2346 movs r3, #70 ; 0x46\n", + " 64e: 2348 movs r3, #72 ; 0x48\n", + " 650: 234a movs r3, #74 ; 0x4a\n", + " 652: 234c movs r3, #76 ; 0x4c\n", + " 654: 234e movs r3, #78 ; 0x4e\n", + " 656: 2350 movs r3, #80 ; 0x50\n", + " 658: 2352 movs r3, #82 ; 0x52\n", + " 65a: 2354 movs r3, #84 ; 0x54\n", + " 65c: 2356 movs r3, #86 ; 0x56\n", + " 65e: 2358 movs r3, #88 ; 0x58\n", + " 660: 235a movs r3, #90 ; 0x5a\n", + " 662: 235c movs r3, #92 ; 0x5c\n", + " 664: 235e movs r3, #94 ; 0x5e\n", + " 666: 2360 movs r3, #96 ; 0x60\n", + " 668: 2362 movs r3, #98 ; 0x62\n", + " 66a: 2364 movs r3, #100 ; 0x64\n", + " 66c: 2366 movs r3, #102 ; 0x66\n", + " 66e: 2368 movs r3, #104 ; 0x68\n", + " 670: 236a movs r3, #106 ; 0x6a\n", + " 672: 236c movs r3, #108 ; 0x6c\n", + " 674: 236e movs r3, #110 ; 0x6e\n", + " 676: 2370 movs r3, #112 ; 0x70\n", + " 678: 2372 movs r3, #114 ; 0x72\n", + " 67a: 2374 movs r3, #116 ; 0x74\n", + " 67c: 2376 movs r3, #118 ; 0x76\n", + " 67e: 2378 movs r3, #120 ; 0x78\n", + " 680: 237a movs r3, #122 ; 0x7a\n", + " 682: 237c movs r3, #124 ; 0x7c\n", + " 684: 237e movs r3, #126 ; 0x7e\n", + " 686: 2380 movs r3, #128 ; 0x80\n", + " 688: 2382 movs r3, #130 ; 0x82\n", + " 68a: 2384 movs r3, #132 ; 0x84\n", + " 68c: 2386 movs r3, #134 ; 0x86\n", + " 68e: 2388 movs r3, #136 ; 0x88\n", + " 690: 238a movs r3, #138 ; 0x8a\n", + " 692: 238c movs r3, #140 ; 0x8c\n", + " 694: 238e movs r3, #142 ; 0x8e\n", + " 696: 2390 movs r3, #144 ; 0x90\n", + " 698: 2392 movs r3, #146 ; 0x92\n", + " 69a: 2394 movs r3, #148 ; 0x94\n", + " 69c: 2396 movs r3, #150 ; 0x96\n", + " 69e: 2398 movs r3, #152 ; 0x98\n", + " 6a0: 239a movs r3, #154 ; 0x9a\n", + " 6a2: 239c movs r3, #156 ; 0x9c\n", + " 6a4: 239e movs r3, #158 ; 0x9e\n", + " 6a6: 23a0 movs r3, #160 ; 0xa0\n", + " 6a8: 23a2 movs r3, #162 ; 0xa2\n", + " 6aa: 23a4 movs r3, #164 ; 0xa4\n", + " 6ac: 23a6 movs r3, #166 ; 0xa6\n", + " 6ae: 23a8 movs r3, #168 ; 0xa8\n", + " 6b0: 23aa movs r3, #170 ; 0xaa\n", + " 6b2: 23ac movs r3, #172 ; 0xac\n", + " 6b4: 23ae movs r3, #174 ; 0xae\n", + " 6b6: 23b0 movs r3, #176 ; 0xb0\n", + " 6b8: 23b2 movs r3, #178 ; 0xb2\n", + " 6ba: 23b4 movs r3, #180 ; 0xb4\n", + " 6bc: 23b6 movs r3, #182 ; 0xb6\n", + " 6be: 23b8 movs r3, #184 ; 0xb8\n", + " 6c0: 23ba movs r3, #186 ; 0xba\n", + " 6c2: 23bc movs r3, #188 ; 0xbc\n", + " 6c4: 23be movs r3, #190 ; 0xbe\n", + " 6c6: 23c0 movs r3, #192 ; 0xc0\n", + " 6c8: 23c2 movs r3, #194 ; 0xc2\n", + " 6ca: 23c4 movs r3, #196 ; 0xc4\n", + " 6cc: 23c6 movs r3, #198 ; 0xc6\n", + " 6ce: 23c8 movs r3, #200 ; 0xc8\n", + " 6d0: 23ca movs r3, #202 ; 0xca\n", + " 6d2: 23cc movs r3, #204 ; 0xcc\n", + " 6d4: 23ce movs r3, #206 ; 0xce\n", + " 6d6: 23d0 movs r3, #208 ; 0xd0\n", + " 6d8: 23d2 movs r3, #210 ; 0xd2\n", + " 6da: 23d4 movs r3, #212 ; 0xd4\n", + " 6dc: 23d6 movs r3, #214 ; 0xd6\n", + " 6de: 23d8 movs r3, #216 ; 0xd8\n", + " 6e0: 23da movs r3, #218 ; 0xda\n", + " 6e2: 23dc movs r3, #220 ; 0xdc\n", + " 6e4: 23de movs r3, #222 ; 0xde\n", + " 6e6: 23e0 movs r3, #224 ; 0xe0\n", + " 6e8: 23e2 movs r3, #226 ; 0xe2\n", + " 6ea: 23e4 movs r3, #228 ; 0xe4\n", + " 6ec: 23e6 movs r3, #230 ; 0xe6\n", + " 6ee: 23e8 movs r3, #232 ; 0xe8\n", + " 6f0: 23ea movs r3, #234 ; 0xea\n", + " 6f2: 23ec movs r3, #236 ; 0xec\n", + " 6f4: 23ee movs r3, #238 ; 0xee\n", + " 6f6: 23f0 movs r3, #240 ; 0xf0\n", + " 6f8: 23f2 movs r3, #242 ; 0xf2\n", + " 6fa: 23f4 movs r3, #244 ; 0xf4\n", + " 6fc: 23f6 movs r3, #246 ; 0xf6\n", + " 6fe: 23f8 movs r3, #248 ; 0xf8\n", + " 700: 23fa movs r3, #250 ; 0xfa\n", + " 702: 23fc movs r3, #252 ; 0xfc\n", + " 704: 23fe movs r3, #254 ; 0xfe\n", + " 706: 2300 movs r3, #0\n", + " 708: 2302 movs r3, #2\n", + " 70a: 2304 movs r3, #4\n", + " 70c: 2306 movs r3, #6\n", + " 70e: 2308 movs r3, #8\n", + " 710: 230a movs r3, #10\n", + " 712: 230c movs r3, #12\n", + " 714: 230e movs r3, #14\n", + " 716: 2310 movs r3, #16\n", + " 718: 2312 movs r3, #18\n", + " 71a: 2314 movs r3, #20\n", + " 71c: 2316 movs r3, #22\n", + " 71e: 2318 movs r3, #24\n", + " 720: 231a movs r3, #26\n", + " 722: 231c movs r3, #28\n", + " 724: 231e movs r3, #30\n", + " 726: 2320 movs r3, #32\n", + " 728: 2322 movs r3, #34 ; 0x22\n", + " 72a: 2324 movs r3, #36 ; 0x24\n", + " 72c: 2326 movs r3, #38 ; 0x26\n", + " 72e: 2328 movs r3, #40 ; 0x28\n", + " 730: 232a movs r3, #42 ; 0x2a\n", + " 732: 232c movs r3, #44 ; 0x2c\n", + " 734: 232e movs r3, #46 ; 0x2e\n", + " 736: 2330 movs r3, #48 ; 0x30\n", + " 738: 2332 movs r3, #50 ; 0x32\n", + " 73a: 2334 movs r3, #52 ; 0x34\n", + " 73c: 2336 movs r3, #54 ; 0x36\n", + " 73e: 2338 movs r3, #56 ; 0x38\n", + " 740: 233a movs r3, #58 ; 0x3a\n", + " 742: 233c movs r3, #60 ; 0x3c\n", + " 744: 233e movs r3, #62 ; 0x3e\n", + " 746: 2340 movs r3, #64 ; 0x40\n", + " 748: 2342 movs r3, #66 ; 0x42\n", + " 74a: 2344 movs r3, #68 ; 0x44\n", + " 74c: 2346 movs r3, #70 ; 0x46\n", + " 74e: 2348 movs r3, #72 ; 0x48\n", + " 750: 234a movs r3, #74 ; 0x4a\n", + " 752: 234c movs r3, #76 ; 0x4c\n", + " 754: 234e movs r3, #78 ; 0x4e\n", + " 756: 2350 movs r3, #80 ; 0x50\n", + " 758: 2352 movs r3, #82 ; 0x52\n", + " 75a: 2354 movs r3, #84 ; 0x54\n", + " 75c: 2356 movs r3, #86 ; 0x56\n", + " 75e: 2358 movs r3, #88 ; 0x58\n", + " 760: 235a movs r3, #90 ; 0x5a\n", + " 762: 235c movs r3, #92 ; 0x5c\n", + " 764: 235e movs r3, #94 ; 0x5e\n", + " 766: 2360 movs r3, #96 ; 0x60\n", + " 768: 2362 movs r3, #98 ; 0x62\n", + " 76a: 2364 movs r3, #100 ; 0x64\n", + " 76c: 2366 movs r3, #102 ; 0x66\n", + " 76e: 2368 movs r3, #104 ; 0x68\n", + " 770: 236a movs r3, #106 ; 0x6a\n", + " 772: 236c movs r3, #108 ; 0x6c\n", + " 774: 236e movs r3, #110 ; 0x6e\n", + " 776: 2370 movs r3, #112 ; 0x70\n", + " 778: 2372 movs r3, #114 ; 0x72\n", + " 77a: 2374 movs r3, #116 ; 0x74\n", + " 77c: 2376 movs r3, #118 ; 0x76\n", + " 77e: 2378 movs r3, #120 ; 0x78\n", + " 780: 237a movs r3, #122 ; 0x7a\n", + " 782: 237c movs r3, #124 ; 0x7c\n", + " 784: 237e movs r3, #126 ; 0x7e\n", + " 786: 2380 movs r3, #128 ; 0x80\n", + " 788: 2382 movs r3, #130 ; 0x82\n", + " 78a: 2384 movs r3, #132 ; 0x84\n", + " 78c: 2386 movs r3, #134 ; 0x86\n", + " 78e: 2388 movs r3, #136 ; 0x88\n", + " 790: 238a movs r3, #138 ; 0x8a\n", + " 792: 238c movs r3, #140 ; 0x8c\n", + " 794: 238e movs r3, #142 ; 0x8e\n", + " 796: 2390 movs r3, #144 ; 0x90\n", + " 798: 2392 movs r3, #146 ; 0x92\n", + " 79a: 2394 movs r3, #148 ; 0x94\n", + " 79c: 2396 movs r3, #150 ; 0x96\n", + " 79e: 2398 movs r3, #152 ; 0x98\n", + " 7a0: 239a movs r3, #154 ; 0x9a\n", + " 7a2: 239c movs r3, #156 ; 0x9c\n", + " 7a4: 239e movs r3, #158 ; 0x9e\n", + " 7a6: 23a0 movs r3, #160 ; 0xa0\n", + " 7a8: 23a2 movs r3, #162 ; 0xa2\n", + " 7aa: 23a4 movs r3, #164 ; 0xa4\n", + " 7ac: 23a6 movs r3, #166 ; 0xa6\n", + " 7ae: 23a8 movs r3, #168 ; 0xa8\n", + " 7b0: 23aa movs r3, #170 ; 0xaa\n", + " 7b2: 23ac movs r3, #172 ; 0xac\n", + " 7b4: 23ae movs r3, #174 ; 0xae\n", + " 7b6: 23b0 movs r3, #176 ; 0xb0\n", + " 7b8: 23b2 movs r3, #178 ; 0xb2\n", + " 7ba: 23b4 movs r3, #180 ; 0xb4\n", + " 7bc: 23b6 movs r3, #182 ; 0xb6\n", + " 7be: 23b8 movs r3, #184 ; 0xb8\n", + " 7c0: 23ba movs r3, #186 ; 0xba\n", + " 7c2: 23bc movs r3, #188 ; 0xbc\n", + " 7c4: 23be movs r3, #190 ; 0xbe\n", + " 7c6: 23c0 movs r3, #192 ; 0xc0\n", + " 7c8: 23c2 movs r3, #194 ; 0xc2\n", + " 7ca: 23c4 movs r3, #196 ; 0xc4\n", + " 7cc: 23c6 movs r3, #198 ; 0xc6\n", + " 7ce: 23c8 movs r3, #200 ; 0xc8\n", + " 7d0: 23ca movs r3, #202 ; 0xca\n", + " 7d2: 23cc movs r3, #204 ; 0xcc\n", + " 7d4: 23ce movs r3, #206 ; 0xce\n", + " 7d6: 23d0 movs r3, #208 ; 0xd0\n", + " 7d8: 23d2 movs r3, #210 ; 0xd2\n", + " 7da: 23d4 movs r3, #212 ; 0xd4\n", + " 7dc: 23d6 movs r3, #214 ; 0xd6\n", + " 7de: 23d8 movs r3, #216 ; 0xd8\n", + " 7e0: 23da movs r3, #218 ; 0xda\n", + " 7e2: 23dc movs r3, #220 ; 0xdc\n", + " 7e4: 23de movs r3, #222 ; 0xde\n", + " 7e6: 23e0 movs r3, #224 ; 0xe0\n", + " 7e8: 23e2 movs r3, #226 ; 0xe2\n", + " 7ea: 23e4 movs r3, #228 ; 0xe4\n", + " 7ec: 23e6 movs r3, #230 ; 0xe6\n", + " 7ee: 23e8 movs r3, #232 ; 0xe8\n", + " 7f0: 23ea movs r3, #234 ; 0xea\n", + " 7f2: 23ec movs r3, #236 ; 0xec\n", + " 7f4: 23ee movs r3, #238 ; 0xee\n", + " 7f6: 23f0 movs r3, #240 ; 0xf0\n", + " 7f8: 23f2 movs r3, #242 ; 0xf2\n", + " 7fa: 23f4 movs r3, #244 ; 0xf4\n", + " 7fc: 23f6 movs r3, #246 ; 0xf6\n", + " 7fe: 23f8 movs r3, #248 ; 0xf8\n", + " 800: 23fa movs r3, #250 ; 0xfa\n", + " 802: 23fc movs r3, #252 ; 0xfc\n", + " 804: 23fe movs r3, #254 ; 0xfe\n", + " 806: 2300 movs r3, #0\n", + " 808: 0011 movs r1, r2\n", + nullptr +}; +const char* MixedBranch32Results[] = { + " 0: f000 bc03 b.w 80a <MixedBranch32+0x80a>\n", + " 4: 2300 movs r3, #0\n", + " 6: 2302 movs r3, #2\n", + " 8: 2304 movs r3, #4\n", + " a: 2306 movs r3, #6\n", + " c: 2308 movs r3, #8\n", + " e: 230a movs r3, #10\n", + " 10: 230c movs r3, #12\n", + " 12: 230e movs r3, #14\n", + " 14: 2310 movs r3, #16\n", + " 16: 2312 movs r3, #18\n", + " 18: 2314 movs r3, #20\n", + " 1a: 2316 movs r3, #22\n", + " 1c: 2318 movs r3, #24\n", + " 1e: 231a movs r3, #26\n", + " 20: 231c movs r3, #28\n", + " 22: 231e movs r3, #30\n", + " 24: 2320 movs r3, #32\n", + " 26: 2322 movs r3, #34 ; 0x22\n", + " 28: 2324 movs r3, #36 ; 0x24\n", + " 2a: 2326 movs r3, #38 ; 0x26\n", + " 2c: 2328 movs r3, #40 ; 0x28\n", + " 2e: 232a movs r3, #42 ; 0x2a\n", + " 30: 232c movs r3, #44 ; 0x2c\n", + " 32: 232e movs r3, #46 ; 0x2e\n", + " 34: 2330 movs r3, #48 ; 0x30\n", + " 36: 2332 movs r3, #50 ; 0x32\n", + " 38: 2334 movs r3, #52 ; 0x34\n", + " 3a: 2336 movs r3, #54 ; 0x36\n", + " 3c: 2338 movs r3, #56 ; 0x38\n", + " 3e: 233a movs r3, #58 ; 0x3a\n", + " 40: 233c movs r3, #60 ; 0x3c\n", + " 42: 233e movs r3, #62 ; 0x3e\n", + " 44: 2340 movs r3, #64 ; 0x40\n", + " 46: 2342 movs r3, #66 ; 0x42\n", + " 48: 2344 movs r3, #68 ; 0x44\n", + " 4a: 2346 movs r3, #70 ; 0x46\n", + " 4c: 2348 movs r3, #72 ; 0x48\n", + " 4e: 234a movs r3, #74 ; 0x4a\n", + " 50: 234c movs r3, #76 ; 0x4c\n", + " 52: 234e movs r3, #78 ; 0x4e\n", + " 54: 2350 movs r3, #80 ; 0x50\n", + " 56: 2352 movs r3, #82 ; 0x52\n", + " 58: 2354 movs r3, #84 ; 0x54\n", + " 5a: 2356 movs r3, #86 ; 0x56\n", + " 5c: 2358 movs r3, #88 ; 0x58\n", + " 5e: 235a movs r3, #90 ; 0x5a\n", + " 60: 235c movs r3, #92 ; 0x5c\n", + " 62: 235e movs r3, #94 ; 0x5e\n", + " 64: 2360 movs r3, #96 ; 0x60\n", + " 66: 2362 movs r3, #98 ; 0x62\n", + " 68: 2364 movs r3, #100 ; 0x64\n", + " 6a: 2366 movs r3, #102 ; 0x66\n", + " 6c: 2368 movs r3, #104 ; 0x68\n", + " 6e: 236a movs r3, #106 ; 0x6a\n", + " 70: 236c movs r3, #108 ; 0x6c\n", + " 72: 236e movs r3, #110 ; 0x6e\n", + " 74: 2370 movs r3, #112 ; 0x70\n", + " 76: 2372 movs r3, #114 ; 0x72\n", + " 78: 2374 movs r3, #116 ; 0x74\n", + " 7a: 2376 movs r3, #118 ; 0x76\n", + " 7c: 2378 movs r3, #120 ; 0x78\n", + " 7e: 237a movs r3, #122 ; 0x7a\n", + " 80: 237c movs r3, #124 ; 0x7c\n", + " 82: 237e movs r3, #126 ; 0x7e\n", + " 84: 2380 movs r3, #128 ; 0x80\n", + " 86: 2382 movs r3, #130 ; 0x82\n", + " 88: 2384 movs r3, #132 ; 0x84\n", + " 8a: 2386 movs r3, #134 ; 0x86\n", + " 8c: 2388 movs r3, #136 ; 0x88\n", + " 8e: 238a movs r3, #138 ; 0x8a\n", + " 90: 238c movs r3, #140 ; 0x8c\n", + " 92: 238e movs r3, #142 ; 0x8e\n", + " 94: 2390 movs r3, #144 ; 0x90\n", + " 96: 2392 movs r3, #146 ; 0x92\n", + " 98: 2394 movs r3, #148 ; 0x94\n", + " 9a: 2396 movs r3, #150 ; 0x96\n", + " 9c: 2398 movs r3, #152 ; 0x98\n", + " 9e: 239a movs r3, #154 ; 0x9a\n", + " a0: 239c movs r3, #156 ; 0x9c\n", + " a2: 239e movs r3, #158 ; 0x9e\n", + " a4: 23a0 movs r3, #160 ; 0xa0\n", + " a6: 23a2 movs r3, #162 ; 0xa2\n", + " a8: 23a4 movs r3, #164 ; 0xa4\n", + " aa: 23a6 movs r3, #166 ; 0xa6\n", + " ac: 23a8 movs r3, #168 ; 0xa8\n", + " ae: 23aa movs r3, #170 ; 0xaa\n", + " b0: 23ac movs r3, #172 ; 0xac\n", + " b2: 23ae movs r3, #174 ; 0xae\n", + " b4: 23b0 movs r3, #176 ; 0xb0\n", + " b6: 23b2 movs r3, #178 ; 0xb2\n", + " b8: 23b4 movs r3, #180 ; 0xb4\n", + " ba: 23b6 movs r3, #182 ; 0xb6\n", + " bc: 23b8 movs r3, #184 ; 0xb8\n", + " be: 23ba movs r3, #186 ; 0xba\n", + " c0: 23bc movs r3, #188 ; 0xbc\n", + " c2: 23be movs r3, #190 ; 0xbe\n", + " c4: 23c0 movs r3, #192 ; 0xc0\n", + " c6: 23c2 movs r3, #194 ; 0xc2\n", + " c8: 23c4 movs r3, #196 ; 0xc4\n", + " ca: 23c6 movs r3, #198 ; 0xc6\n", + " cc: 23c8 movs r3, #200 ; 0xc8\n", + " ce: 23ca movs r3, #202 ; 0xca\n", + " d0: 23cc movs r3, #204 ; 0xcc\n", + " d2: 23ce movs r3, #206 ; 0xce\n", + " d4: 23d0 movs r3, #208 ; 0xd0\n", + " d6: 23d2 movs r3, #210 ; 0xd2\n", + " d8: 23d4 movs r3, #212 ; 0xd4\n", + " da: 23d6 movs r3, #214 ; 0xd6\n", + " dc: 23d8 movs r3, #216 ; 0xd8\n", + " de: 23da movs r3, #218 ; 0xda\n", + " e0: 23dc movs r3, #220 ; 0xdc\n", + " e2: 23de movs r3, #222 ; 0xde\n", + " e4: 23e0 movs r3, #224 ; 0xe0\n", + " e6: 23e2 movs r3, #226 ; 0xe2\n", + " e8: 23e4 movs r3, #228 ; 0xe4\n", + " ea: 23e6 movs r3, #230 ; 0xe6\n", + " ec: 23e8 movs r3, #232 ; 0xe8\n", + " ee: 23ea movs r3, #234 ; 0xea\n", + " f0: 23ec movs r3, #236 ; 0xec\n", + " f2: 23ee movs r3, #238 ; 0xee\n", + " f4: 23f0 movs r3, #240 ; 0xf0\n", + " f6: 23f2 movs r3, #242 ; 0xf2\n", + " f8: 23f4 movs r3, #244 ; 0xf4\n", + " fa: 23f6 movs r3, #246 ; 0xf6\n", + " fc: 23f8 movs r3, #248 ; 0xf8\n", + " fe: 23fa movs r3, #250 ; 0xfa\n", + " 100: 23fc movs r3, #252 ; 0xfc\n", + " 102: 23fe movs r3, #254 ; 0xfe\n", + " 104: 2300 movs r3, #0\n", + " 106: 2302 movs r3, #2\n", + " 108: 2304 movs r3, #4\n", + " 10a: 2306 movs r3, #6\n", + " 10c: 2308 movs r3, #8\n", + " 10e: 230a movs r3, #10\n", + " 110: 230c movs r3, #12\n", + " 112: 230e movs r3, #14\n", + " 114: 2310 movs r3, #16\n", + " 116: 2312 movs r3, #18\n", + " 118: 2314 movs r3, #20\n", + " 11a: 2316 movs r3, #22\n", + " 11c: 2318 movs r3, #24\n", + " 11e: 231a movs r3, #26\n", + " 120: 231c movs r3, #28\n", + " 122: 231e movs r3, #30\n", + " 124: 2320 movs r3, #32\n", + " 126: 2322 movs r3, #34 ; 0x22\n", + " 128: 2324 movs r3, #36 ; 0x24\n", + " 12a: 2326 movs r3, #38 ; 0x26\n", + " 12c: 2328 movs r3, #40 ; 0x28\n", + " 12e: 232a movs r3, #42 ; 0x2a\n", + " 130: 232c movs r3, #44 ; 0x2c\n", + " 132: 232e movs r3, #46 ; 0x2e\n", + " 134: 2330 movs r3, #48 ; 0x30\n", + " 136: 2332 movs r3, #50 ; 0x32\n", + " 138: 2334 movs r3, #52 ; 0x34\n", + " 13a: 2336 movs r3, #54 ; 0x36\n", + " 13c: 2338 movs r3, #56 ; 0x38\n", + " 13e: 233a movs r3, #58 ; 0x3a\n", + " 140: 233c movs r3, #60 ; 0x3c\n", + " 142: 233e movs r3, #62 ; 0x3e\n", + " 144: 2340 movs r3, #64 ; 0x40\n", + " 146: 2342 movs r3, #66 ; 0x42\n", + " 148: 2344 movs r3, #68 ; 0x44\n", + " 14a: 2346 movs r3, #70 ; 0x46\n", + " 14c: 2348 movs r3, #72 ; 0x48\n", + " 14e: 234a movs r3, #74 ; 0x4a\n", + " 150: 234c movs r3, #76 ; 0x4c\n", + " 152: 234e movs r3, #78 ; 0x4e\n", + " 154: 2350 movs r3, #80 ; 0x50\n", + " 156: 2352 movs r3, #82 ; 0x52\n", + " 158: 2354 movs r3, #84 ; 0x54\n", + " 15a: 2356 movs r3, #86 ; 0x56\n", + " 15c: 2358 movs r3, #88 ; 0x58\n", + " 15e: 235a movs r3, #90 ; 0x5a\n", + " 160: 235c movs r3, #92 ; 0x5c\n", + " 162: 235e movs r3, #94 ; 0x5e\n", + " 164: 2360 movs r3, #96 ; 0x60\n", + " 166: 2362 movs r3, #98 ; 0x62\n", + " 168: 2364 movs r3, #100 ; 0x64\n", + " 16a: 2366 movs r3, #102 ; 0x66\n", + " 16c: 2368 movs r3, #104 ; 0x68\n", + " 16e: 236a movs r3, #106 ; 0x6a\n", + " 170: 236c movs r3, #108 ; 0x6c\n", + " 172: 236e movs r3, #110 ; 0x6e\n", + " 174: 2370 movs r3, #112 ; 0x70\n", + " 176: 2372 movs r3, #114 ; 0x72\n", + " 178: 2374 movs r3, #116 ; 0x74\n", + " 17a: 2376 movs r3, #118 ; 0x76\n", + " 17c: 2378 movs r3, #120 ; 0x78\n", + " 17e: 237a movs r3, #122 ; 0x7a\n", + " 180: 237c movs r3, #124 ; 0x7c\n", + " 182: 237e movs r3, #126 ; 0x7e\n", + " 184: 2380 movs r3, #128 ; 0x80\n", + " 186: 2382 movs r3, #130 ; 0x82\n", + " 188: 2384 movs r3, #132 ; 0x84\n", + " 18a: 2386 movs r3, #134 ; 0x86\n", + " 18c: 2388 movs r3, #136 ; 0x88\n", + " 18e: 238a movs r3, #138 ; 0x8a\n", + " 190: 238c movs r3, #140 ; 0x8c\n", + " 192: 238e movs r3, #142 ; 0x8e\n", + " 194: 2390 movs r3, #144 ; 0x90\n", + " 196: 2392 movs r3, #146 ; 0x92\n", + " 198: 2394 movs r3, #148 ; 0x94\n", + " 19a: 2396 movs r3, #150 ; 0x96\n", + " 19c: 2398 movs r3, #152 ; 0x98\n", + " 19e: 239a movs r3, #154 ; 0x9a\n", + " 1a0: 239c movs r3, #156 ; 0x9c\n", + " 1a2: 239e movs r3, #158 ; 0x9e\n", + " 1a4: 23a0 movs r3, #160 ; 0xa0\n", + " 1a6: 23a2 movs r3, #162 ; 0xa2\n", + " 1a8: 23a4 movs r3, #164 ; 0xa4\n", + " 1aa: 23a6 movs r3, #166 ; 0xa6\n", + " 1ac: 23a8 movs r3, #168 ; 0xa8\n", + " 1ae: 23aa movs r3, #170 ; 0xaa\n", + " 1b0: 23ac movs r3, #172 ; 0xac\n", + " 1b2: 23ae movs r3, #174 ; 0xae\n", + " 1b4: 23b0 movs r3, #176 ; 0xb0\n", + " 1b6: 23b2 movs r3, #178 ; 0xb2\n", + " 1b8: 23b4 movs r3, #180 ; 0xb4\n", + " 1ba: 23b6 movs r3, #182 ; 0xb6\n", + " 1bc: 23b8 movs r3, #184 ; 0xb8\n", + " 1be: 23ba movs r3, #186 ; 0xba\n", + " 1c0: 23bc movs r3, #188 ; 0xbc\n", + " 1c2: 23be movs r3, #190 ; 0xbe\n", + " 1c4: 23c0 movs r3, #192 ; 0xc0\n", + " 1c6: 23c2 movs r3, #194 ; 0xc2\n", + " 1c8: 23c4 movs r3, #196 ; 0xc4\n", + " 1ca: 23c6 movs r3, #198 ; 0xc6\n", + " 1cc: 23c8 movs r3, #200 ; 0xc8\n", + " 1ce: 23ca movs r3, #202 ; 0xca\n", + " 1d0: 23cc movs r3, #204 ; 0xcc\n", + " 1d2: 23ce movs r3, #206 ; 0xce\n", + " 1d4: 23d0 movs r3, #208 ; 0xd0\n", + " 1d6: 23d2 movs r3, #210 ; 0xd2\n", + " 1d8: 23d4 movs r3, #212 ; 0xd4\n", + " 1da: 23d6 movs r3, #214 ; 0xd6\n", + " 1dc: 23d8 movs r3, #216 ; 0xd8\n", + " 1de: 23da movs r3, #218 ; 0xda\n", + " 1e0: 23dc movs r3, #220 ; 0xdc\n", + " 1e2: 23de movs r3, #222 ; 0xde\n", + " 1e4: 23e0 movs r3, #224 ; 0xe0\n", + " 1e6: 23e2 movs r3, #226 ; 0xe2\n", + " 1e8: 23e4 movs r3, #228 ; 0xe4\n", + " 1ea: 23e6 movs r3, #230 ; 0xe6\n", + " 1ec: 23e8 movs r3, #232 ; 0xe8\n", + " 1ee: 23ea movs r3, #234 ; 0xea\n", + " 1f0: 23ec movs r3, #236 ; 0xec\n", + " 1f2: 23ee movs r3, #238 ; 0xee\n", + " 1f4: 23f0 movs r3, #240 ; 0xf0\n", + " 1f6: 23f2 movs r3, #242 ; 0xf2\n", + " 1f8: 23f4 movs r3, #244 ; 0xf4\n", + " 1fa: 23f6 movs r3, #246 ; 0xf6\n", + " 1fc: 23f8 movs r3, #248 ; 0xf8\n", + " 1fe: 23fa movs r3, #250 ; 0xfa\n", + " 200: 23fc movs r3, #252 ; 0xfc\n", + " 202: 23fe movs r3, #254 ; 0xfe\n", + " 204: 2300 movs r3, #0\n", + " 206: 2302 movs r3, #2\n", + " 208: 2304 movs r3, #4\n", + " 20a: 2306 movs r3, #6\n", + " 20c: 2308 movs r3, #8\n", + " 20e: 230a movs r3, #10\n", + " 210: 230c movs r3, #12\n", + " 212: 230e movs r3, #14\n", + " 214: 2310 movs r3, #16\n", + " 216: 2312 movs r3, #18\n", + " 218: 2314 movs r3, #20\n", + " 21a: 2316 movs r3, #22\n", + " 21c: 2318 movs r3, #24\n", + " 21e: 231a movs r3, #26\n", + " 220: 231c movs r3, #28\n", + " 222: 231e movs r3, #30\n", + " 224: 2320 movs r3, #32\n", + " 226: 2322 movs r3, #34 ; 0x22\n", + " 228: 2324 movs r3, #36 ; 0x24\n", + " 22a: 2326 movs r3, #38 ; 0x26\n", + " 22c: 2328 movs r3, #40 ; 0x28\n", + " 22e: 232a movs r3, #42 ; 0x2a\n", + " 230: 232c movs r3, #44 ; 0x2c\n", + " 232: 232e movs r3, #46 ; 0x2e\n", + " 234: 2330 movs r3, #48 ; 0x30\n", + " 236: 2332 movs r3, #50 ; 0x32\n", + " 238: 2334 movs r3, #52 ; 0x34\n", + " 23a: 2336 movs r3, #54 ; 0x36\n", + " 23c: 2338 movs r3, #56 ; 0x38\n", + " 23e: 233a movs r3, #58 ; 0x3a\n", + " 240: 233c movs r3, #60 ; 0x3c\n", + " 242: 233e movs r3, #62 ; 0x3e\n", + " 244: 2340 movs r3, #64 ; 0x40\n", + " 246: 2342 movs r3, #66 ; 0x42\n", + " 248: 2344 movs r3, #68 ; 0x44\n", + " 24a: 2346 movs r3, #70 ; 0x46\n", + " 24c: 2348 movs r3, #72 ; 0x48\n", + " 24e: 234a movs r3, #74 ; 0x4a\n", + " 250: 234c movs r3, #76 ; 0x4c\n", + " 252: 234e movs r3, #78 ; 0x4e\n", + " 254: 2350 movs r3, #80 ; 0x50\n", + " 256: 2352 movs r3, #82 ; 0x52\n", + " 258: 2354 movs r3, #84 ; 0x54\n", + " 25a: 2356 movs r3, #86 ; 0x56\n", + " 25c: 2358 movs r3, #88 ; 0x58\n", + " 25e: 235a movs r3, #90 ; 0x5a\n", + " 260: 235c movs r3, #92 ; 0x5c\n", + " 262: 235e movs r3, #94 ; 0x5e\n", + " 264: 2360 movs r3, #96 ; 0x60\n", + " 266: 2362 movs r3, #98 ; 0x62\n", + " 268: 2364 movs r3, #100 ; 0x64\n", + " 26a: 2366 movs r3, #102 ; 0x66\n", + " 26c: 2368 movs r3, #104 ; 0x68\n", + " 26e: 236a movs r3, #106 ; 0x6a\n", + " 270: 236c movs r3, #108 ; 0x6c\n", + " 272: 236e movs r3, #110 ; 0x6e\n", + " 274: 2370 movs r3, #112 ; 0x70\n", + " 276: 2372 movs r3, #114 ; 0x72\n", + " 278: 2374 movs r3, #116 ; 0x74\n", + " 27a: 2376 movs r3, #118 ; 0x76\n", + " 27c: 2378 movs r3, #120 ; 0x78\n", + " 27e: 237a movs r3, #122 ; 0x7a\n", + " 280: 237c movs r3, #124 ; 0x7c\n", + " 282: 237e movs r3, #126 ; 0x7e\n", + " 284: 2380 movs r3, #128 ; 0x80\n", + " 286: 2382 movs r3, #130 ; 0x82\n", + " 288: 2384 movs r3, #132 ; 0x84\n", + " 28a: 2386 movs r3, #134 ; 0x86\n", + " 28c: 2388 movs r3, #136 ; 0x88\n", + " 28e: 238a movs r3, #138 ; 0x8a\n", + " 290: 238c movs r3, #140 ; 0x8c\n", + " 292: 238e movs r3, #142 ; 0x8e\n", + " 294: 2390 movs r3, #144 ; 0x90\n", + " 296: 2392 movs r3, #146 ; 0x92\n", + " 298: 2394 movs r3, #148 ; 0x94\n", + " 29a: 2396 movs r3, #150 ; 0x96\n", + " 29c: 2398 movs r3, #152 ; 0x98\n", + " 29e: 239a movs r3, #154 ; 0x9a\n", + " 2a0: 239c movs r3, #156 ; 0x9c\n", + " 2a2: 239e movs r3, #158 ; 0x9e\n", + " 2a4: 23a0 movs r3, #160 ; 0xa0\n", + " 2a6: 23a2 movs r3, #162 ; 0xa2\n", + " 2a8: 23a4 movs r3, #164 ; 0xa4\n", + " 2aa: 23a6 movs r3, #166 ; 0xa6\n", + " 2ac: 23a8 movs r3, #168 ; 0xa8\n", + " 2ae: 23aa movs r3, #170 ; 0xaa\n", + " 2b0: 23ac movs r3, #172 ; 0xac\n", + " 2b2: 23ae movs r3, #174 ; 0xae\n", + " 2b4: 23b0 movs r3, #176 ; 0xb0\n", + " 2b6: 23b2 movs r3, #178 ; 0xb2\n", + " 2b8: 23b4 movs r3, #180 ; 0xb4\n", + " 2ba: 23b6 movs r3, #182 ; 0xb6\n", + " 2bc: 23b8 movs r3, #184 ; 0xb8\n", + " 2be: 23ba movs r3, #186 ; 0xba\n", + " 2c0: 23bc movs r3, #188 ; 0xbc\n", + " 2c2: 23be movs r3, #190 ; 0xbe\n", + " 2c4: 23c0 movs r3, #192 ; 0xc0\n", + " 2c6: 23c2 movs r3, #194 ; 0xc2\n", + " 2c8: 23c4 movs r3, #196 ; 0xc4\n", + " 2ca: 23c6 movs r3, #198 ; 0xc6\n", + " 2cc: 23c8 movs r3, #200 ; 0xc8\n", + " 2ce: 23ca movs r3, #202 ; 0xca\n", + " 2d0: 23cc movs r3, #204 ; 0xcc\n", + " 2d2: 23ce movs r3, #206 ; 0xce\n", + " 2d4: 23d0 movs r3, #208 ; 0xd0\n", + " 2d6: 23d2 movs r3, #210 ; 0xd2\n", + " 2d8: 23d4 movs r3, #212 ; 0xd4\n", + " 2da: 23d6 movs r3, #214 ; 0xd6\n", + " 2dc: 23d8 movs r3, #216 ; 0xd8\n", + " 2de: 23da movs r3, #218 ; 0xda\n", + " 2e0: 23dc movs r3, #220 ; 0xdc\n", + " 2e2: 23de movs r3, #222 ; 0xde\n", + " 2e4: 23e0 movs r3, #224 ; 0xe0\n", + " 2e6: 23e2 movs r3, #226 ; 0xe2\n", + " 2e8: 23e4 movs r3, #228 ; 0xe4\n", + " 2ea: 23e6 movs r3, #230 ; 0xe6\n", + " 2ec: 23e8 movs r3, #232 ; 0xe8\n", + " 2ee: 23ea movs r3, #234 ; 0xea\n", + " 2f0: 23ec movs r3, #236 ; 0xec\n", + " 2f2: 23ee movs r3, #238 ; 0xee\n", + " 2f4: 23f0 movs r3, #240 ; 0xf0\n", + " 2f6: 23f2 movs r3, #242 ; 0xf2\n", + " 2f8: 23f4 movs r3, #244 ; 0xf4\n", + " 2fa: 23f6 movs r3, #246 ; 0xf6\n", + " 2fc: 23f8 movs r3, #248 ; 0xf8\n", + " 2fe: 23fa movs r3, #250 ; 0xfa\n", + " 300: 23fc movs r3, #252 ; 0xfc\n", + " 302: 23fe movs r3, #254 ; 0xfe\n", + " 304: 2300 movs r3, #0\n", + " 306: 2302 movs r3, #2\n", + " 308: 2304 movs r3, #4\n", + " 30a: 2306 movs r3, #6\n", + " 30c: 2308 movs r3, #8\n", + " 30e: 230a movs r3, #10\n", + " 310: 230c movs r3, #12\n", + " 312: 230e movs r3, #14\n", + " 314: 2310 movs r3, #16\n", + " 316: 2312 movs r3, #18\n", + " 318: 2314 movs r3, #20\n", + " 31a: 2316 movs r3, #22\n", + " 31c: 2318 movs r3, #24\n", + " 31e: 231a movs r3, #26\n", + " 320: 231c movs r3, #28\n", + " 322: 231e movs r3, #30\n", + " 324: 2320 movs r3, #32\n", + " 326: 2322 movs r3, #34 ; 0x22\n", + " 328: 2324 movs r3, #36 ; 0x24\n", + " 32a: 2326 movs r3, #38 ; 0x26\n", + " 32c: 2328 movs r3, #40 ; 0x28\n", + " 32e: 232a movs r3, #42 ; 0x2a\n", + " 330: 232c movs r3, #44 ; 0x2c\n", + " 332: 232e movs r3, #46 ; 0x2e\n", + " 334: 2330 movs r3, #48 ; 0x30\n", + " 336: 2332 movs r3, #50 ; 0x32\n", + " 338: 2334 movs r3, #52 ; 0x34\n", + " 33a: 2336 movs r3, #54 ; 0x36\n", + " 33c: 2338 movs r3, #56 ; 0x38\n", + " 33e: 233a movs r3, #58 ; 0x3a\n", + " 340: 233c movs r3, #60 ; 0x3c\n", + " 342: 233e movs r3, #62 ; 0x3e\n", + " 344: 2340 movs r3, #64 ; 0x40\n", + " 346: 2342 movs r3, #66 ; 0x42\n", + " 348: 2344 movs r3, #68 ; 0x44\n", + " 34a: 2346 movs r3, #70 ; 0x46\n", + " 34c: 2348 movs r3, #72 ; 0x48\n", + " 34e: 234a movs r3, #74 ; 0x4a\n", + " 350: 234c movs r3, #76 ; 0x4c\n", + " 352: 234e movs r3, #78 ; 0x4e\n", + " 354: 2350 movs r3, #80 ; 0x50\n", + " 356: 2352 movs r3, #82 ; 0x52\n", + " 358: 2354 movs r3, #84 ; 0x54\n", + " 35a: 2356 movs r3, #86 ; 0x56\n", + " 35c: 2358 movs r3, #88 ; 0x58\n", + " 35e: 235a movs r3, #90 ; 0x5a\n", + " 360: 235c movs r3, #92 ; 0x5c\n", + " 362: 235e movs r3, #94 ; 0x5e\n", + " 364: 2360 movs r3, #96 ; 0x60\n", + " 366: 2362 movs r3, #98 ; 0x62\n", + " 368: 2364 movs r3, #100 ; 0x64\n", + " 36a: 2366 movs r3, #102 ; 0x66\n", + " 36c: 2368 movs r3, #104 ; 0x68\n", + " 36e: 236a movs r3, #106 ; 0x6a\n", + " 370: 236c movs r3, #108 ; 0x6c\n", + " 372: 236e movs r3, #110 ; 0x6e\n", + " 374: 2370 movs r3, #112 ; 0x70\n", + " 376: 2372 movs r3, #114 ; 0x72\n", + " 378: 2374 movs r3, #116 ; 0x74\n", + " 37a: 2376 movs r3, #118 ; 0x76\n", + " 37c: 2378 movs r3, #120 ; 0x78\n", + " 37e: 237a movs r3, #122 ; 0x7a\n", + " 380: 237c movs r3, #124 ; 0x7c\n", + " 382: 237e movs r3, #126 ; 0x7e\n", + " 384: 2380 movs r3, #128 ; 0x80\n", + " 386: 2382 movs r3, #130 ; 0x82\n", + " 388: 2384 movs r3, #132 ; 0x84\n", + " 38a: 2386 movs r3, #134 ; 0x86\n", + " 38c: 2388 movs r3, #136 ; 0x88\n", + " 38e: 238a movs r3, #138 ; 0x8a\n", + " 390: 238c movs r3, #140 ; 0x8c\n", + " 392: 238e movs r3, #142 ; 0x8e\n", + " 394: 2390 movs r3, #144 ; 0x90\n", + " 396: 2392 movs r3, #146 ; 0x92\n", + " 398: 2394 movs r3, #148 ; 0x94\n", + " 39a: 2396 movs r3, #150 ; 0x96\n", + " 39c: 2398 movs r3, #152 ; 0x98\n", + " 39e: 239a movs r3, #154 ; 0x9a\n", + " 3a0: 239c movs r3, #156 ; 0x9c\n", + " 3a2: 239e movs r3, #158 ; 0x9e\n", + " 3a4: 23a0 movs r3, #160 ; 0xa0\n", + " 3a6: 23a2 movs r3, #162 ; 0xa2\n", + " 3a8: 23a4 movs r3, #164 ; 0xa4\n", + " 3aa: 23a6 movs r3, #166 ; 0xa6\n", + " 3ac: 23a8 movs r3, #168 ; 0xa8\n", + " 3ae: 23aa movs r3, #170 ; 0xaa\n", + " 3b0: 23ac movs r3, #172 ; 0xac\n", + " 3b2: 23ae movs r3, #174 ; 0xae\n", + " 3b4: 23b0 movs r3, #176 ; 0xb0\n", + " 3b6: 23b2 movs r3, #178 ; 0xb2\n", + " 3b8: 23b4 movs r3, #180 ; 0xb4\n", + " 3ba: 23b6 movs r3, #182 ; 0xb6\n", + " 3bc: 23b8 movs r3, #184 ; 0xb8\n", + " 3be: 23ba movs r3, #186 ; 0xba\n", + " 3c0: 23bc movs r3, #188 ; 0xbc\n", + " 3c2: 23be movs r3, #190 ; 0xbe\n", + " 3c4: 23c0 movs r3, #192 ; 0xc0\n", + " 3c6: 23c2 movs r3, #194 ; 0xc2\n", + " 3c8: 23c4 movs r3, #196 ; 0xc4\n", + " 3ca: 23c6 movs r3, #198 ; 0xc6\n", + " 3cc: 23c8 movs r3, #200 ; 0xc8\n", + " 3ce: 23ca movs r3, #202 ; 0xca\n", + " 3d0: 23cc movs r3, #204 ; 0xcc\n", + " 3d2: 23ce movs r3, #206 ; 0xce\n", + " 3d4: 23d0 movs r3, #208 ; 0xd0\n", + " 3d6: 23d2 movs r3, #210 ; 0xd2\n", + " 3d8: 23d4 movs r3, #212 ; 0xd4\n", + " 3da: 23d6 movs r3, #214 ; 0xd6\n", + " 3dc: 23d8 movs r3, #216 ; 0xd8\n", + " 3de: 23da movs r3, #218 ; 0xda\n", + " 3e0: 23dc movs r3, #220 ; 0xdc\n", + " 3e2: 23de movs r3, #222 ; 0xde\n", + " 3e4: 23e0 movs r3, #224 ; 0xe0\n", + " 3e6: 23e2 movs r3, #226 ; 0xe2\n", + " 3e8: 23e4 movs r3, #228 ; 0xe4\n", + " 3ea: 23e6 movs r3, #230 ; 0xe6\n", + " 3ec: 23e8 movs r3, #232 ; 0xe8\n", + " 3ee: 23ea movs r3, #234 ; 0xea\n", + " 3f0: 23ec movs r3, #236 ; 0xec\n", + " 3f2: 23ee movs r3, #238 ; 0xee\n", + " 3f4: 23f0 movs r3, #240 ; 0xf0\n", + " 3f6: 23f2 movs r3, #242 ; 0xf2\n", + " 3f8: 23f4 movs r3, #244 ; 0xf4\n", + " 3fa: 23f6 movs r3, #246 ; 0xf6\n", + " 3fc: 23f8 movs r3, #248 ; 0xf8\n", + " 3fe: 23fa movs r3, #250 ; 0xfa\n", + " 400: 23fc movs r3, #252 ; 0xfc\n", + " 402: 23fe movs r3, #254 ; 0xfe\n", + " 404: 2300 movs r3, #0\n", + " 406: 2302 movs r3, #2\n", + " 408: 2304 movs r3, #4\n", + " 40a: 2306 movs r3, #6\n", + " 40c: 2308 movs r3, #8\n", + " 40e: 230a movs r3, #10\n", + " 410: 230c movs r3, #12\n", + " 412: 230e movs r3, #14\n", + " 414: 2310 movs r3, #16\n", + " 416: 2312 movs r3, #18\n", + " 418: 2314 movs r3, #20\n", + " 41a: 2316 movs r3, #22\n", + " 41c: 2318 movs r3, #24\n", + " 41e: 231a movs r3, #26\n", + " 420: 231c movs r3, #28\n", + " 422: 231e movs r3, #30\n", + " 424: 2320 movs r3, #32\n", + " 426: 2322 movs r3, #34 ; 0x22\n", + " 428: 2324 movs r3, #36 ; 0x24\n", + " 42a: 2326 movs r3, #38 ; 0x26\n", + " 42c: 2328 movs r3, #40 ; 0x28\n", + " 42e: 232a movs r3, #42 ; 0x2a\n", + " 430: 232c movs r3, #44 ; 0x2c\n", + " 432: 232e movs r3, #46 ; 0x2e\n", + " 434: 2330 movs r3, #48 ; 0x30\n", + " 436: 2332 movs r3, #50 ; 0x32\n", + " 438: 2334 movs r3, #52 ; 0x34\n", + " 43a: 2336 movs r3, #54 ; 0x36\n", + " 43c: 2338 movs r3, #56 ; 0x38\n", + " 43e: 233a movs r3, #58 ; 0x3a\n", + " 440: 233c movs r3, #60 ; 0x3c\n", + " 442: 233e movs r3, #62 ; 0x3e\n", + " 444: 2340 movs r3, #64 ; 0x40\n", + " 446: 2342 movs r3, #66 ; 0x42\n", + " 448: 2344 movs r3, #68 ; 0x44\n", + " 44a: 2346 movs r3, #70 ; 0x46\n", + " 44c: 2348 movs r3, #72 ; 0x48\n", + " 44e: 234a movs r3, #74 ; 0x4a\n", + " 450: 234c movs r3, #76 ; 0x4c\n", + " 452: 234e movs r3, #78 ; 0x4e\n", + " 454: 2350 movs r3, #80 ; 0x50\n", + " 456: 2352 movs r3, #82 ; 0x52\n", + " 458: 2354 movs r3, #84 ; 0x54\n", + " 45a: 2356 movs r3, #86 ; 0x56\n", + " 45c: 2358 movs r3, #88 ; 0x58\n", + " 45e: 235a movs r3, #90 ; 0x5a\n", + " 460: 235c movs r3, #92 ; 0x5c\n", + " 462: 235e movs r3, #94 ; 0x5e\n", + " 464: 2360 movs r3, #96 ; 0x60\n", + " 466: 2362 movs r3, #98 ; 0x62\n", + " 468: 2364 movs r3, #100 ; 0x64\n", + " 46a: 2366 movs r3, #102 ; 0x66\n", + " 46c: 2368 movs r3, #104 ; 0x68\n", + " 46e: 236a movs r3, #106 ; 0x6a\n", + " 470: 236c movs r3, #108 ; 0x6c\n", + " 472: 236e movs r3, #110 ; 0x6e\n", + " 474: 2370 movs r3, #112 ; 0x70\n", + " 476: 2372 movs r3, #114 ; 0x72\n", + " 478: 2374 movs r3, #116 ; 0x74\n", + " 47a: 2376 movs r3, #118 ; 0x76\n", + " 47c: 2378 movs r3, #120 ; 0x78\n", + " 47e: 237a movs r3, #122 ; 0x7a\n", + " 480: 237c movs r3, #124 ; 0x7c\n", + " 482: 237e movs r3, #126 ; 0x7e\n", + " 484: 2380 movs r3, #128 ; 0x80\n", + " 486: 2382 movs r3, #130 ; 0x82\n", + " 488: 2384 movs r3, #132 ; 0x84\n", + " 48a: 2386 movs r3, #134 ; 0x86\n", + " 48c: 2388 movs r3, #136 ; 0x88\n", + " 48e: 238a movs r3, #138 ; 0x8a\n", + " 490: 238c movs r3, #140 ; 0x8c\n", + " 492: 238e movs r3, #142 ; 0x8e\n", + " 494: 2390 movs r3, #144 ; 0x90\n", + " 496: 2392 movs r3, #146 ; 0x92\n", + " 498: 2394 movs r3, #148 ; 0x94\n", + " 49a: 2396 movs r3, #150 ; 0x96\n", + " 49c: 2398 movs r3, #152 ; 0x98\n", + " 49e: 239a movs r3, #154 ; 0x9a\n", + " 4a0: 239c movs r3, #156 ; 0x9c\n", + " 4a2: 239e movs r3, #158 ; 0x9e\n", + " 4a4: 23a0 movs r3, #160 ; 0xa0\n", + " 4a6: 23a2 movs r3, #162 ; 0xa2\n", + " 4a8: 23a4 movs r3, #164 ; 0xa4\n", + " 4aa: 23a6 movs r3, #166 ; 0xa6\n", + " 4ac: 23a8 movs r3, #168 ; 0xa8\n", + " 4ae: 23aa movs r3, #170 ; 0xaa\n", + " 4b0: 23ac movs r3, #172 ; 0xac\n", + " 4b2: 23ae movs r3, #174 ; 0xae\n", + " 4b4: 23b0 movs r3, #176 ; 0xb0\n", + " 4b6: 23b2 movs r3, #178 ; 0xb2\n", + " 4b8: 23b4 movs r3, #180 ; 0xb4\n", + " 4ba: 23b6 movs r3, #182 ; 0xb6\n", + " 4bc: 23b8 movs r3, #184 ; 0xb8\n", + " 4be: 23ba movs r3, #186 ; 0xba\n", + " 4c0: 23bc movs r3, #188 ; 0xbc\n", + " 4c2: 23be movs r3, #190 ; 0xbe\n", + " 4c4: 23c0 movs r3, #192 ; 0xc0\n", + " 4c6: 23c2 movs r3, #194 ; 0xc2\n", + " 4c8: 23c4 movs r3, #196 ; 0xc4\n", + " 4ca: 23c6 movs r3, #198 ; 0xc6\n", + " 4cc: 23c8 movs r3, #200 ; 0xc8\n", + " 4ce: 23ca movs r3, #202 ; 0xca\n", + " 4d0: 23cc movs r3, #204 ; 0xcc\n", + " 4d2: 23ce movs r3, #206 ; 0xce\n", + " 4d4: 23d0 movs r3, #208 ; 0xd0\n", + " 4d6: 23d2 movs r3, #210 ; 0xd2\n", + " 4d8: 23d4 movs r3, #212 ; 0xd4\n", + " 4da: 23d6 movs r3, #214 ; 0xd6\n", + " 4dc: 23d8 movs r3, #216 ; 0xd8\n", + " 4de: 23da movs r3, #218 ; 0xda\n", + " 4e0: 23dc movs r3, #220 ; 0xdc\n", + " 4e2: 23de movs r3, #222 ; 0xde\n", + " 4e4: 23e0 movs r3, #224 ; 0xe0\n", + " 4e6: 23e2 movs r3, #226 ; 0xe2\n", + " 4e8: 23e4 movs r3, #228 ; 0xe4\n", + " 4ea: 23e6 movs r3, #230 ; 0xe6\n", + " 4ec: 23e8 movs r3, #232 ; 0xe8\n", + " 4ee: 23ea movs r3, #234 ; 0xea\n", + " 4f0: 23ec movs r3, #236 ; 0xec\n", + " 4f2: 23ee movs r3, #238 ; 0xee\n", + " 4f4: 23f0 movs r3, #240 ; 0xf0\n", + " 4f6: 23f2 movs r3, #242 ; 0xf2\n", + " 4f8: 23f4 movs r3, #244 ; 0xf4\n", + " 4fa: 23f6 movs r3, #246 ; 0xf6\n", + " 4fc: 23f8 movs r3, #248 ; 0xf8\n", + " 4fe: 23fa movs r3, #250 ; 0xfa\n", + " 500: 23fc movs r3, #252 ; 0xfc\n", + " 502: 23fe movs r3, #254 ; 0xfe\n", + " 504: 2300 movs r3, #0\n", + " 506: 2302 movs r3, #2\n", + " 508: 2304 movs r3, #4\n", + " 50a: 2306 movs r3, #6\n", + " 50c: 2308 movs r3, #8\n", + " 50e: 230a movs r3, #10\n", + " 510: 230c movs r3, #12\n", + " 512: 230e movs r3, #14\n", + " 514: 2310 movs r3, #16\n", + " 516: 2312 movs r3, #18\n", + " 518: 2314 movs r3, #20\n", + " 51a: 2316 movs r3, #22\n", + " 51c: 2318 movs r3, #24\n", + " 51e: 231a movs r3, #26\n", + " 520: 231c movs r3, #28\n", + " 522: 231e movs r3, #30\n", + " 524: 2320 movs r3, #32\n", + " 526: 2322 movs r3, #34 ; 0x22\n", + " 528: 2324 movs r3, #36 ; 0x24\n", + " 52a: 2326 movs r3, #38 ; 0x26\n", + " 52c: 2328 movs r3, #40 ; 0x28\n", + " 52e: 232a movs r3, #42 ; 0x2a\n", + " 530: 232c movs r3, #44 ; 0x2c\n", + " 532: 232e movs r3, #46 ; 0x2e\n", + " 534: 2330 movs r3, #48 ; 0x30\n", + " 536: 2332 movs r3, #50 ; 0x32\n", + " 538: 2334 movs r3, #52 ; 0x34\n", + " 53a: 2336 movs r3, #54 ; 0x36\n", + " 53c: 2338 movs r3, #56 ; 0x38\n", + " 53e: 233a movs r3, #58 ; 0x3a\n", + " 540: 233c movs r3, #60 ; 0x3c\n", + " 542: 233e movs r3, #62 ; 0x3e\n", + " 544: 2340 movs r3, #64 ; 0x40\n", + " 546: 2342 movs r3, #66 ; 0x42\n", + " 548: 2344 movs r3, #68 ; 0x44\n", + " 54a: 2346 movs r3, #70 ; 0x46\n", + " 54c: 2348 movs r3, #72 ; 0x48\n", + " 54e: 234a movs r3, #74 ; 0x4a\n", + " 550: 234c movs r3, #76 ; 0x4c\n", + " 552: 234e movs r3, #78 ; 0x4e\n", + " 554: 2350 movs r3, #80 ; 0x50\n", + " 556: 2352 movs r3, #82 ; 0x52\n", + " 558: 2354 movs r3, #84 ; 0x54\n", + " 55a: 2356 movs r3, #86 ; 0x56\n", + " 55c: 2358 movs r3, #88 ; 0x58\n", + " 55e: 235a movs r3, #90 ; 0x5a\n", + " 560: 235c movs r3, #92 ; 0x5c\n", + " 562: 235e movs r3, #94 ; 0x5e\n", + " 564: 2360 movs r3, #96 ; 0x60\n", + " 566: 2362 movs r3, #98 ; 0x62\n", + " 568: 2364 movs r3, #100 ; 0x64\n", + " 56a: 2366 movs r3, #102 ; 0x66\n", + " 56c: 2368 movs r3, #104 ; 0x68\n", + " 56e: 236a movs r3, #106 ; 0x6a\n", + " 570: 236c movs r3, #108 ; 0x6c\n", + " 572: 236e movs r3, #110 ; 0x6e\n", + " 574: 2370 movs r3, #112 ; 0x70\n", + " 576: 2372 movs r3, #114 ; 0x72\n", + " 578: 2374 movs r3, #116 ; 0x74\n", + " 57a: 2376 movs r3, #118 ; 0x76\n", + " 57c: 2378 movs r3, #120 ; 0x78\n", + " 57e: 237a movs r3, #122 ; 0x7a\n", + " 580: 237c movs r3, #124 ; 0x7c\n", + " 582: 237e movs r3, #126 ; 0x7e\n", + " 584: 2380 movs r3, #128 ; 0x80\n", + " 586: 2382 movs r3, #130 ; 0x82\n", + " 588: 2384 movs r3, #132 ; 0x84\n", + " 58a: 2386 movs r3, #134 ; 0x86\n", + " 58c: 2388 movs r3, #136 ; 0x88\n", + " 58e: 238a movs r3, #138 ; 0x8a\n", + " 590: 238c movs r3, #140 ; 0x8c\n", + " 592: 238e movs r3, #142 ; 0x8e\n", + " 594: 2390 movs r3, #144 ; 0x90\n", + " 596: 2392 movs r3, #146 ; 0x92\n", + " 598: 2394 movs r3, #148 ; 0x94\n", + " 59a: 2396 movs r3, #150 ; 0x96\n", + " 59c: 2398 movs r3, #152 ; 0x98\n", + " 59e: 239a movs r3, #154 ; 0x9a\n", + " 5a0: 239c movs r3, #156 ; 0x9c\n", + " 5a2: 239e movs r3, #158 ; 0x9e\n", + " 5a4: 23a0 movs r3, #160 ; 0xa0\n", + " 5a6: 23a2 movs r3, #162 ; 0xa2\n", + " 5a8: 23a4 movs r3, #164 ; 0xa4\n", + " 5aa: 23a6 movs r3, #166 ; 0xa6\n", + " 5ac: 23a8 movs r3, #168 ; 0xa8\n", + " 5ae: 23aa movs r3, #170 ; 0xaa\n", + " 5b0: 23ac movs r3, #172 ; 0xac\n", + " 5b2: 23ae movs r3, #174 ; 0xae\n", + " 5b4: 23b0 movs r3, #176 ; 0xb0\n", + " 5b6: 23b2 movs r3, #178 ; 0xb2\n", + " 5b8: 23b4 movs r3, #180 ; 0xb4\n", + " 5ba: 23b6 movs r3, #182 ; 0xb6\n", + " 5bc: 23b8 movs r3, #184 ; 0xb8\n", + " 5be: 23ba movs r3, #186 ; 0xba\n", + " 5c0: 23bc movs r3, #188 ; 0xbc\n", + " 5c2: 23be movs r3, #190 ; 0xbe\n", + " 5c4: 23c0 movs r3, #192 ; 0xc0\n", + " 5c6: 23c2 movs r3, #194 ; 0xc2\n", + " 5c8: 23c4 movs r3, #196 ; 0xc4\n", + " 5ca: 23c6 movs r3, #198 ; 0xc6\n", + " 5cc: 23c8 movs r3, #200 ; 0xc8\n", + " 5ce: 23ca movs r3, #202 ; 0xca\n", + " 5d0: 23cc movs r3, #204 ; 0xcc\n", + " 5d2: 23ce movs r3, #206 ; 0xce\n", + " 5d4: 23d0 movs r3, #208 ; 0xd0\n", + " 5d6: 23d2 movs r3, #210 ; 0xd2\n", + " 5d8: 23d4 movs r3, #212 ; 0xd4\n", + " 5da: 23d6 movs r3, #214 ; 0xd6\n", + " 5dc: 23d8 movs r3, #216 ; 0xd8\n", + " 5de: 23da movs r3, #218 ; 0xda\n", + " 5e0: 23dc movs r3, #220 ; 0xdc\n", + " 5e2: 23de movs r3, #222 ; 0xde\n", + " 5e4: 23e0 movs r3, #224 ; 0xe0\n", + " 5e6: 23e2 movs r3, #226 ; 0xe2\n", + " 5e8: 23e4 movs r3, #228 ; 0xe4\n", + " 5ea: 23e6 movs r3, #230 ; 0xe6\n", + " 5ec: 23e8 movs r3, #232 ; 0xe8\n", + " 5ee: 23ea movs r3, #234 ; 0xea\n", + " 5f0: 23ec movs r3, #236 ; 0xec\n", + " 5f2: 23ee movs r3, #238 ; 0xee\n", + " 5f4: 23f0 movs r3, #240 ; 0xf0\n", + " 5f6: 23f2 movs r3, #242 ; 0xf2\n", + " 5f8: 23f4 movs r3, #244 ; 0xf4\n", + " 5fa: 23f6 movs r3, #246 ; 0xf6\n", + " 5fc: 23f8 movs r3, #248 ; 0xf8\n", + " 5fe: 23fa movs r3, #250 ; 0xfa\n", + " 600: 23fc movs r3, #252 ; 0xfc\n", + " 602: 23fe movs r3, #254 ; 0xfe\n", + " 604: 2300 movs r3, #0\n", + " 606: 2302 movs r3, #2\n", + " 608: 2304 movs r3, #4\n", + " 60a: 2306 movs r3, #6\n", + " 60c: 2308 movs r3, #8\n", + " 60e: 230a movs r3, #10\n", + " 610: 230c movs r3, #12\n", + " 612: 230e movs r3, #14\n", + " 614: 2310 movs r3, #16\n", + " 616: 2312 movs r3, #18\n", + " 618: 2314 movs r3, #20\n", + " 61a: 2316 movs r3, #22\n", + " 61c: 2318 movs r3, #24\n", + " 61e: 231a movs r3, #26\n", + " 620: 231c movs r3, #28\n", + " 622: 231e movs r3, #30\n", + " 624: 2320 movs r3, #32\n", + " 626: 2322 movs r3, #34 ; 0x22\n", + " 628: 2324 movs r3, #36 ; 0x24\n", + " 62a: 2326 movs r3, #38 ; 0x26\n", + " 62c: 2328 movs r3, #40 ; 0x28\n", + " 62e: 232a movs r3, #42 ; 0x2a\n", + " 630: 232c movs r3, #44 ; 0x2c\n", + " 632: 232e movs r3, #46 ; 0x2e\n", + " 634: 2330 movs r3, #48 ; 0x30\n", + " 636: 2332 movs r3, #50 ; 0x32\n", + " 638: 2334 movs r3, #52 ; 0x34\n", + " 63a: 2336 movs r3, #54 ; 0x36\n", + " 63c: 2338 movs r3, #56 ; 0x38\n", + " 63e: 233a movs r3, #58 ; 0x3a\n", + " 640: 233c movs r3, #60 ; 0x3c\n", + " 642: 233e movs r3, #62 ; 0x3e\n", + " 644: 2340 movs r3, #64 ; 0x40\n", + " 646: 2342 movs r3, #66 ; 0x42\n", + " 648: 2344 movs r3, #68 ; 0x44\n", + " 64a: 2346 movs r3, #70 ; 0x46\n", + " 64c: 2348 movs r3, #72 ; 0x48\n", + " 64e: 234a movs r3, #74 ; 0x4a\n", + " 650: 234c movs r3, #76 ; 0x4c\n", + " 652: 234e movs r3, #78 ; 0x4e\n", + " 654: 2350 movs r3, #80 ; 0x50\n", + " 656: 2352 movs r3, #82 ; 0x52\n", + " 658: 2354 movs r3, #84 ; 0x54\n", + " 65a: 2356 movs r3, #86 ; 0x56\n", + " 65c: 2358 movs r3, #88 ; 0x58\n", + " 65e: 235a movs r3, #90 ; 0x5a\n", + " 660: 235c movs r3, #92 ; 0x5c\n", + " 662: 235e movs r3, #94 ; 0x5e\n", + " 664: 2360 movs r3, #96 ; 0x60\n", + " 666: 2362 movs r3, #98 ; 0x62\n", + " 668: 2364 movs r3, #100 ; 0x64\n", + " 66a: 2366 movs r3, #102 ; 0x66\n", + " 66c: 2368 movs r3, #104 ; 0x68\n", + " 66e: 236a movs r3, #106 ; 0x6a\n", + " 670: 236c movs r3, #108 ; 0x6c\n", + " 672: 236e movs r3, #110 ; 0x6e\n", + " 674: 2370 movs r3, #112 ; 0x70\n", + " 676: 2372 movs r3, #114 ; 0x72\n", + " 678: 2374 movs r3, #116 ; 0x74\n", + " 67a: 2376 movs r3, #118 ; 0x76\n", + " 67c: 2378 movs r3, #120 ; 0x78\n", + " 67e: 237a movs r3, #122 ; 0x7a\n", + " 680: 237c movs r3, #124 ; 0x7c\n", + " 682: 237e movs r3, #126 ; 0x7e\n", + " 684: 2380 movs r3, #128 ; 0x80\n", + " 686: 2382 movs r3, #130 ; 0x82\n", + " 688: 2384 movs r3, #132 ; 0x84\n", + " 68a: 2386 movs r3, #134 ; 0x86\n", + " 68c: 2388 movs r3, #136 ; 0x88\n", + " 68e: 238a movs r3, #138 ; 0x8a\n", + " 690: 238c movs r3, #140 ; 0x8c\n", + " 692: 238e movs r3, #142 ; 0x8e\n", + " 694: 2390 movs r3, #144 ; 0x90\n", + " 696: 2392 movs r3, #146 ; 0x92\n", + " 698: 2394 movs r3, #148 ; 0x94\n", + " 69a: 2396 movs r3, #150 ; 0x96\n", + " 69c: 2398 movs r3, #152 ; 0x98\n", + " 69e: 239a movs r3, #154 ; 0x9a\n", + " 6a0: 239c movs r3, #156 ; 0x9c\n", + " 6a2: 239e movs r3, #158 ; 0x9e\n", + " 6a4: 23a0 movs r3, #160 ; 0xa0\n", + " 6a6: 23a2 movs r3, #162 ; 0xa2\n", + " 6a8: 23a4 movs r3, #164 ; 0xa4\n", + " 6aa: 23a6 movs r3, #166 ; 0xa6\n", + " 6ac: 23a8 movs r3, #168 ; 0xa8\n", + " 6ae: 23aa movs r3, #170 ; 0xaa\n", + " 6b0: 23ac movs r3, #172 ; 0xac\n", + " 6b2: 23ae movs r3, #174 ; 0xae\n", + " 6b4: 23b0 movs r3, #176 ; 0xb0\n", + " 6b6: 23b2 movs r3, #178 ; 0xb2\n", + " 6b8: 23b4 movs r3, #180 ; 0xb4\n", + " 6ba: 23b6 movs r3, #182 ; 0xb6\n", + " 6bc: 23b8 movs r3, #184 ; 0xb8\n", + " 6be: 23ba movs r3, #186 ; 0xba\n", + " 6c0: 23bc movs r3, #188 ; 0xbc\n", + " 6c2: 23be movs r3, #190 ; 0xbe\n", + " 6c4: 23c0 movs r3, #192 ; 0xc0\n", + " 6c6: 23c2 movs r3, #194 ; 0xc2\n", + " 6c8: 23c4 movs r3, #196 ; 0xc4\n", + " 6ca: 23c6 movs r3, #198 ; 0xc6\n", + " 6cc: 23c8 movs r3, #200 ; 0xc8\n", + " 6ce: 23ca movs r3, #202 ; 0xca\n", + " 6d0: 23cc movs r3, #204 ; 0xcc\n", + " 6d2: 23ce movs r3, #206 ; 0xce\n", + " 6d4: 23d0 movs r3, #208 ; 0xd0\n", + " 6d6: 23d2 movs r3, #210 ; 0xd2\n", + " 6d8: 23d4 movs r3, #212 ; 0xd4\n", + " 6da: 23d6 movs r3, #214 ; 0xd6\n", + " 6dc: 23d8 movs r3, #216 ; 0xd8\n", + " 6de: 23da movs r3, #218 ; 0xda\n", + " 6e0: 23dc movs r3, #220 ; 0xdc\n", + " 6e2: 23de movs r3, #222 ; 0xde\n", + " 6e4: 23e0 movs r3, #224 ; 0xe0\n", + " 6e6: 23e2 movs r3, #226 ; 0xe2\n", + " 6e8: 23e4 movs r3, #228 ; 0xe4\n", + " 6ea: 23e6 movs r3, #230 ; 0xe6\n", + " 6ec: 23e8 movs r3, #232 ; 0xe8\n", + " 6ee: 23ea movs r3, #234 ; 0xea\n", + " 6f0: 23ec movs r3, #236 ; 0xec\n", + " 6f2: 23ee movs r3, #238 ; 0xee\n", + " 6f4: 23f0 movs r3, #240 ; 0xf0\n", + " 6f6: 23f2 movs r3, #242 ; 0xf2\n", + " 6f8: 23f4 movs r3, #244 ; 0xf4\n", + " 6fa: 23f6 movs r3, #246 ; 0xf6\n", + " 6fc: 23f8 movs r3, #248 ; 0xf8\n", + " 6fe: 23fa movs r3, #250 ; 0xfa\n", + " 700: 23fc movs r3, #252 ; 0xfc\n", + " 702: 23fe movs r3, #254 ; 0xfe\n", + " 704: 2300 movs r3, #0\n", + " 706: 2302 movs r3, #2\n", + " 708: 2304 movs r3, #4\n", + " 70a: 2306 movs r3, #6\n", + " 70c: 2308 movs r3, #8\n", + " 70e: 230a movs r3, #10\n", + " 710: 230c movs r3, #12\n", + " 712: 230e movs r3, #14\n", + " 714: 2310 movs r3, #16\n", + " 716: 2312 movs r3, #18\n", + " 718: 2314 movs r3, #20\n", + " 71a: 2316 movs r3, #22\n", + " 71c: 2318 movs r3, #24\n", + " 71e: 231a movs r3, #26\n", + " 720: 231c movs r3, #28\n", + " 722: 231e movs r3, #30\n", + " 724: 2320 movs r3, #32\n", + " 726: 2322 movs r3, #34 ; 0x22\n", + " 728: 2324 movs r3, #36 ; 0x24\n", + " 72a: 2326 movs r3, #38 ; 0x26\n", + " 72c: 2328 movs r3, #40 ; 0x28\n", + " 72e: 232a movs r3, #42 ; 0x2a\n", + " 730: 232c movs r3, #44 ; 0x2c\n", + " 732: 232e movs r3, #46 ; 0x2e\n", + " 734: 2330 movs r3, #48 ; 0x30\n", + " 736: 2332 movs r3, #50 ; 0x32\n", + " 738: 2334 movs r3, #52 ; 0x34\n", + " 73a: 2336 movs r3, #54 ; 0x36\n", + " 73c: 2338 movs r3, #56 ; 0x38\n", + " 73e: 233a movs r3, #58 ; 0x3a\n", + " 740: 233c movs r3, #60 ; 0x3c\n", + " 742: 233e movs r3, #62 ; 0x3e\n", + " 744: 2340 movs r3, #64 ; 0x40\n", + " 746: 2342 movs r3, #66 ; 0x42\n", + " 748: 2344 movs r3, #68 ; 0x44\n", + " 74a: 2346 movs r3, #70 ; 0x46\n", + " 74c: 2348 movs r3, #72 ; 0x48\n", + " 74e: 234a movs r3, #74 ; 0x4a\n", + " 750: 234c movs r3, #76 ; 0x4c\n", + " 752: 234e movs r3, #78 ; 0x4e\n", + " 754: 2350 movs r3, #80 ; 0x50\n", + " 756: 2352 movs r3, #82 ; 0x52\n", + " 758: 2354 movs r3, #84 ; 0x54\n", + " 75a: 2356 movs r3, #86 ; 0x56\n", + " 75c: 2358 movs r3, #88 ; 0x58\n", + " 75e: 235a movs r3, #90 ; 0x5a\n", + " 760: 235c movs r3, #92 ; 0x5c\n", + " 762: 235e movs r3, #94 ; 0x5e\n", + " 764: 2360 movs r3, #96 ; 0x60\n", + " 766: 2362 movs r3, #98 ; 0x62\n", + " 768: 2364 movs r3, #100 ; 0x64\n", + " 76a: 2366 movs r3, #102 ; 0x66\n", + " 76c: 2368 movs r3, #104 ; 0x68\n", + " 76e: 236a movs r3, #106 ; 0x6a\n", + " 770: 236c movs r3, #108 ; 0x6c\n", + " 772: 236e movs r3, #110 ; 0x6e\n", + " 774: 2370 movs r3, #112 ; 0x70\n", + " 776: 2372 movs r3, #114 ; 0x72\n", + " 778: 2374 movs r3, #116 ; 0x74\n", + " 77a: 2376 movs r3, #118 ; 0x76\n", + " 77c: 2378 movs r3, #120 ; 0x78\n", + " 77e: 237a movs r3, #122 ; 0x7a\n", + " 780: 237c movs r3, #124 ; 0x7c\n", + " 782: 237e movs r3, #126 ; 0x7e\n", + " 784: 2380 movs r3, #128 ; 0x80\n", + " 786: 2382 movs r3, #130 ; 0x82\n", + " 788: 2384 movs r3, #132 ; 0x84\n", + " 78a: 2386 movs r3, #134 ; 0x86\n", + " 78c: 2388 movs r3, #136 ; 0x88\n", + " 78e: 238a movs r3, #138 ; 0x8a\n", + " 790: 238c movs r3, #140 ; 0x8c\n", + " 792: 238e movs r3, #142 ; 0x8e\n", + " 794: 2390 movs r3, #144 ; 0x90\n", + " 796: 2392 movs r3, #146 ; 0x92\n", + " 798: 2394 movs r3, #148 ; 0x94\n", + " 79a: 2396 movs r3, #150 ; 0x96\n", + " 79c: 2398 movs r3, #152 ; 0x98\n", + " 79e: 239a movs r3, #154 ; 0x9a\n", + " 7a0: 239c movs r3, #156 ; 0x9c\n", + " 7a2: 239e movs r3, #158 ; 0x9e\n", + " 7a4: 23a0 movs r3, #160 ; 0xa0\n", + " 7a6: 23a2 movs r3, #162 ; 0xa2\n", + " 7a8: 23a4 movs r3, #164 ; 0xa4\n", + " 7aa: 23a6 movs r3, #166 ; 0xa6\n", + " 7ac: 23a8 movs r3, #168 ; 0xa8\n", + " 7ae: 23aa movs r3, #170 ; 0xaa\n", + " 7b0: 23ac movs r3, #172 ; 0xac\n", + " 7b2: 23ae movs r3, #174 ; 0xae\n", + " 7b4: 23b0 movs r3, #176 ; 0xb0\n", + " 7b6: 23b2 movs r3, #178 ; 0xb2\n", + " 7b8: 23b4 movs r3, #180 ; 0xb4\n", + " 7ba: 23b6 movs r3, #182 ; 0xb6\n", + " 7bc: 23b8 movs r3, #184 ; 0xb8\n", + " 7be: 23ba movs r3, #186 ; 0xba\n", + " 7c0: 23bc movs r3, #188 ; 0xbc\n", + " 7c2: 23be movs r3, #190 ; 0xbe\n", + " 7c4: 23c0 movs r3, #192 ; 0xc0\n", + " 7c6: 23c2 movs r3, #194 ; 0xc2\n", + " 7c8: 23c4 movs r3, #196 ; 0xc4\n", + " 7ca: 23c6 movs r3, #198 ; 0xc6\n", + " 7cc: 23c8 movs r3, #200 ; 0xc8\n", + " 7ce: 23ca movs r3, #202 ; 0xca\n", + " 7d0: 23cc movs r3, #204 ; 0xcc\n", + " 7d2: 23ce movs r3, #206 ; 0xce\n", + " 7d4: 23d0 movs r3, #208 ; 0xd0\n", + " 7d6: 23d2 movs r3, #210 ; 0xd2\n", + " 7d8: 23d4 movs r3, #212 ; 0xd4\n", + " 7da: 23d6 movs r3, #214 ; 0xd6\n", + " 7dc: 23d8 movs r3, #216 ; 0xd8\n", + " 7de: 23da movs r3, #218 ; 0xda\n", + " 7e0: 23dc movs r3, #220 ; 0xdc\n", + " 7e2: 23de movs r3, #222 ; 0xde\n", + " 7e4: 23e0 movs r3, #224 ; 0xe0\n", + " 7e6: 23e2 movs r3, #226 ; 0xe2\n", + " 7e8: 23e4 movs r3, #228 ; 0xe4\n", + " 7ea: 23e6 movs r3, #230 ; 0xe6\n", + " 7ec: 23e8 movs r3, #232 ; 0xe8\n", + " 7ee: 23ea movs r3, #234 ; 0xea\n", + " 7f0: 23ec movs r3, #236 ; 0xec\n", + " 7f2: 23ee movs r3, #238 ; 0xee\n", + " 7f4: 23f0 movs r3, #240 ; 0xf0\n", + " 7f6: 23f2 movs r3, #242 ; 0xf2\n", + " 7f8: 23f4 movs r3, #244 ; 0xf4\n", + " 7fa: 23f6 movs r3, #246 ; 0xf6\n", + " 7fc: 23f8 movs r3, #248 ; 0xf8\n", + " 7fe: 23fa movs r3, #250 ; 0xfa\n", + " 800: 23fc movs r3, #252 ; 0xfc\n", + " 802: 23fe movs r3, #254 ; 0xfe\n", + " 804: 2300 movs r3, #0\n", + " 806: f7ff bbfd b.w 4 <MixedBranch32+0x4>\n", + " 80a: 0011 movs r1, r2\n", + nullptr +}; +std::map<std::string, const char**> test_results; +void setup_results() { + test_results["SimpleMov"] = SimpleMovResults; + test_results["SimpleMov32"] = SimpleMov32Results; + test_results["SimpleMovAdd"] = SimpleMovAddResults; + test_results["DataProcessingRegister"] = DataProcessingRegisterResults; + test_results["DataProcessingImmediate"] = DataProcessingImmediateResults; + test_results["DataProcessingModifiedImmediate"] = DataProcessingModifiedImmediateResults; + test_results["DataProcessingModifiedImmediates"] = DataProcessingModifiedImmediatesResults; + test_results["DataProcessingShiftedRegister"] = DataProcessingShiftedRegisterResults; + test_results["BasicLoad"] = BasicLoadResults; + test_results["BasicStore"] = BasicStoreResults; + test_results["ComplexLoad"] = ComplexLoadResults; + test_results["ComplexStore"] = ComplexStoreResults; + test_results["NegativeLoadStore"] = NegativeLoadStoreResults; + test_results["SimpleLoadStoreDual"] = SimpleLoadStoreDualResults; + test_results["ComplexLoadStoreDual"] = ComplexLoadStoreDualResults; + test_results["NegativeLoadStoreDual"] = NegativeLoadStoreDualResults; + test_results["SimpleBranch"] = SimpleBranchResults; + test_results["LongBranch"] = LongBranchResults; + test_results["LoadMultiple"] = LoadMultipleResults; + test_results["StoreMultiple"] = StoreMultipleResults; + test_results["MovWMovT"] = MovWMovTResults; + test_results["SpecialAddSub"] = SpecialAddSubResults; + test_results["StoreToOffset"] = StoreToOffsetResults; + test_results["IfThen"] = IfThenResults; + test_results["CbzCbnz"] = CbzCbnzResults; + test_results["Multiply"] = MultiplyResults; + test_results["Divide"] = DivideResults; + test_results["VMov"] = VMovResults; + test_results["BasicFloatingPoint"] = BasicFloatingPointResults; + test_results["FloatingPointConversions"] = FloatingPointConversionsResults; + test_results["FloatingPointComparisons"] = FloatingPointComparisonsResults; + test_results["Calls"] = CallsResults; + test_results["Breakpoint"] = BreakpointResults; + test_results["StrR1"] = StrR1Results; + test_results["VPushPop"] = VPushPopResults; + test_results["Max16BitBranch"] = Max16BitBranchResults; + test_results["Branch32"] = Branch32Results; + test_results["CompareAndBranchMax"] = CompareAndBranchMaxResults; + test_results["CompareAndBranchRelocation16"] = CompareAndBranchRelocation16Results; + test_results["CompareAndBranchRelocation32"] = CompareAndBranchRelocation32Results; + test_results["MixedBranch32"] = MixedBranch32Results; +} |