// Copyright 2015, VIXL authors // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ARM Limited nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #include } #include #include #include #include #include #include "utils-vixl.h" #include "aarch32/constants-aarch32.h" #include "aarch32/instructions-aarch32.h" #include "aarch32/operands-aarch32.h" #include "aarch32/assembler-aarch32.h" namespace vixl { namespace aarch32 { void Assembler::EmitT32_16(uint16_t instr) { VIXL_ASSERT(buffer_.Is16bitAligned()); buffer_.Emit16(instr); } void Assembler::EmitT32_32(uint32_t instr) { VIXL_ASSERT(buffer_.Is16bitAligned()); buffer_.Emit16(static_cast(instr >> 16)); buffer_.Emit16(static_cast(instr & 0xffff)); } void Assembler::EmitA32(uint32_t instr) { VIXL_ASSERT(buffer_.Is32bitAligned()); buffer_.Emit32(instr); } #ifdef VIXL_DEBUG void Assembler::PerformCheckIT(Condition condition) { if (it_mask_ == 0) { VIXL_ASSERT(IsUsingA32() || condition.Is(al)); } else { VIXL_ASSERT(condition.Is(first_condition_)); first_condition_ = Condition((first_condition_.GetCondition() & 0xe) | (it_mask_ >> 3)); // For A32, AdavanceIT() is not called by the assembler. We must call it // in order to check that IT instructions are used consistently with // the following conditional instructions. if (IsUsingA32()) AdvanceIT(); } } #endif void Assembler::BindHelper(Label* label) { VIXL_ASSERT(!label->IsBound()); label->Bind(GetCursorOffset(), GetInstructionSetInUse()); for (Label::ForwardRefList::iterator ref = label->GetFirstForwardRef(); ref != label->GetEndForwardRef(); ref++) { EncodeLabelFor(*ref, label); } if (label->IsInVeneerPool()) { label->GetVeneerPoolManager()->RemoveLabel(label); } } uint32_t Assembler::Link(uint32_t instr, Label* label, const Label::LabelEmitOperator& op) { label->SetReferenced(); if (label->IsBound()) { return op.Encode(instr, GetCursorOffset() + GetArchitectureStatePCOffset(), label); } label->AddForwardRef(GetCursorOffset(), GetInstructionSetInUse(), op); return instr; } void Assembler::EncodeLabelFor(const Label::ForwardReference& forward, Label* label) { const uint32_t location = forward.GetLocation(); const uint32_t from = location + forward.GetStatePCOffset(); const Label::LabelEmitOperator& encoder = forward.GetEmitOperator(); if (forward.IsUsingT32()) { uint16_t* instr_ptr = buffer_.GetOffsetAddress(location); if (Is16BitEncoding(instr_ptr[0])) { // The Encode methods always deals with uint32_t types so we need // to explicitely cast it. uint32_t instr = static_cast(instr_ptr[0]); instr = encoder.Encode(instr, from, label); // The Encode method should not ever set the top 16 bits. VIXL_ASSERT((instr & ~0xffff) == 0); instr_ptr[0] = static_cast(instr); } else { uint32_t instr = instr_ptr[1] | (static_cast(instr_ptr[0]) << 16); instr = encoder.Encode(instr, from, label); instr_ptr[0] = static_cast(instr >> 16); instr_ptr[1] = static_cast(instr); } } else { uint32_t* instr_ptr = buffer_.GetOffsetAddress(location); instr_ptr[0] = encoder.Encode(instr_ptr[0], from, label); } } // Start of generated code. class Dt_L_imm6_1 : public EncodingValue { uint32_t type_; public: explicit Dt_L_imm6_1(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_L_imm6_1::Dt_L_imm6_1(DataType dt) { switch (dt.GetValue()) { case S8: type_ = 0x0; SetEncodingValue(0x1); break; case U8: type_ = 0x1; SetEncodingValue(0x1); break; case S16: type_ = 0x0; SetEncodingValue(0x2); break; case U16: type_ = 0x1; SetEncodingValue(0x2); break; case S32: type_ = 0x0; SetEncodingValue(0x4); break; case U32: type_ = 0x1; SetEncodingValue(0x4); break; case S64: type_ = 0x0; SetEncodingValue(0x8); break; case U64: type_ = 0x1; SetEncodingValue(0x8); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_L_imm6_2 : public EncodingValue { uint32_t type_; public: explicit Dt_L_imm6_2(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_L_imm6_2::Dt_L_imm6_2(DataType dt) { switch (dt.GetValue()) { case S8: type_ = 0x1; SetEncodingValue(0x1); break; case S16: type_ = 0x1; SetEncodingValue(0x2); break; case S32: type_ = 0x1; SetEncodingValue(0x4); break; case S64: type_ = 0x1; SetEncodingValue(0x8); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_L_imm6_3 : public EncodingValue { public: explicit Dt_L_imm6_3(DataType dt); }; Dt_L_imm6_3::Dt_L_imm6_3(DataType dt) { switch (dt.GetValue()) { case I8: SetEncodingValue(0x1); break; case I16: SetEncodingValue(0x2); break; case I32: SetEncodingValue(0x4); break; case I64: SetEncodingValue(0x8); break; default: break; } } class Dt_L_imm6_4 : public EncodingValue { public: explicit Dt_L_imm6_4(DataType dt); }; Dt_L_imm6_4::Dt_L_imm6_4(DataType dt) { switch (dt.GetValue()) { case Untyped8: SetEncodingValue(0x1); break; case Untyped16: SetEncodingValue(0x2); break; case Untyped32: SetEncodingValue(0x4); break; case Untyped64: SetEncodingValue(0x8); break; default: break; } } class Dt_imm6_1 : public EncodingValue { uint32_t type_; public: explicit Dt_imm6_1(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_imm6_1::Dt_imm6_1(DataType dt) { switch (dt.GetValue()) { case S16: type_ = 0x0; SetEncodingValue(0x1); break; case U16: type_ = 0x1; SetEncodingValue(0x1); break; case S32: type_ = 0x0; SetEncodingValue(0x2); break; case U32: type_ = 0x1; SetEncodingValue(0x2); break; case S64: type_ = 0x0; SetEncodingValue(0x4); break; case U64: type_ = 0x1; SetEncodingValue(0x4); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_imm6_2 : public EncodingValue { uint32_t type_; public: explicit Dt_imm6_2(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_imm6_2::Dt_imm6_2(DataType dt) { switch (dt.GetValue()) { case S16: type_ = 0x1; SetEncodingValue(0x1); break; case S32: type_ = 0x1; SetEncodingValue(0x2); break; case S64: type_ = 0x1; SetEncodingValue(0x4); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_imm6_3 : public EncodingValue { public: explicit Dt_imm6_3(DataType dt); }; Dt_imm6_3::Dt_imm6_3(DataType dt) { switch (dt.GetValue()) { case I16: SetEncodingValue(0x1); break; case I32: SetEncodingValue(0x2); break; case I64: SetEncodingValue(0x4); break; default: break; } } class Dt_imm6_4 : public EncodingValue { uint32_t type_; public: explicit Dt_imm6_4(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_imm6_4::Dt_imm6_4(DataType dt) { switch (dt.GetValue()) { case S8: type_ = 0x0; SetEncodingValue(0x1); break; case U8: type_ = 0x1; SetEncodingValue(0x1); break; case S16: type_ = 0x0; SetEncodingValue(0x2); break; case U16: type_ = 0x1; SetEncodingValue(0x2); break; case S32: type_ = 0x0; SetEncodingValue(0x4); break; case U32: type_ = 0x1; SetEncodingValue(0x4); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_op_U_size_1 : public EncodingValue { public: explicit Dt_op_U_size_1(DataType dt); }; Dt_op_U_size_1::Dt_op_U_size_1(DataType dt) { switch (dt.GetValue()) { case S8: SetEncodingValue(0x0); break; case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; case U8: SetEncodingValue(0x4); break; case U16: SetEncodingValue(0x5); break; case U32: SetEncodingValue(0x6); break; case P8: SetEncodingValue(0x8); break; case P64: SetEncodingValue(0xa); break; default: break; } } class Dt_op_size_1 : public EncodingValue { public: explicit Dt_op_size_1(DataType dt); }; Dt_op_size_1::Dt_op_size_1(DataType dt) { switch (dt.GetValue()) { case I8: SetEncodingValue(0x0); break; case I16: SetEncodingValue(0x1); break; case I32: SetEncodingValue(0x2); break; case P8: SetEncodingValue(0x4); break; default: break; } } class Dt_op_size_2 : public EncodingValue { public: explicit Dt_op_size_2(DataType dt); }; Dt_op_size_2::Dt_op_size_2(DataType dt) { switch (dt.GetValue()) { case S8: SetEncodingValue(0x0); break; case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; case U8: SetEncodingValue(0x4); break; case U16: SetEncodingValue(0x5); break; case U32: SetEncodingValue(0x6); break; default: break; } } class Dt_op_size_3 : public EncodingValue { public: explicit Dt_op_size_3(DataType dt); }; Dt_op_size_3::Dt_op_size_3(DataType dt) { switch (dt.GetValue()) { case S16: SetEncodingValue(0x0); break; case S32: SetEncodingValue(0x1); break; case S64: SetEncodingValue(0x2); break; case U16: SetEncodingValue(0x4); break; case U32: SetEncodingValue(0x5); break; case U64: SetEncodingValue(0x6); break; default: break; } } class Dt_U_imm3H_1 : public EncodingValue { public: explicit Dt_U_imm3H_1(DataType dt); }; Dt_U_imm3H_1::Dt_U_imm3H_1(DataType dt) { switch (dt.GetValue()) { case S8: SetEncodingValue(0x1); break; case S16: SetEncodingValue(0x2); break; case S32: SetEncodingValue(0x4); break; case U8: SetEncodingValue(0x9); break; case U16: SetEncodingValue(0xa); break; case U32: SetEncodingValue(0xc); break; default: break; } } class Dt_U_opc1_opc2_1 : public EncodingValue { public: explicit Dt_U_opc1_opc2_1(DataType dt, const DRegisterLane& lane); }; Dt_U_opc1_opc2_1::Dt_U_opc1_opc2_1(DataType dt, const DRegisterLane& lane) { switch (dt.GetValue()) { case S8: if ((lane.GetLane() & 7) != lane.GetLane()) { return; } SetEncodingValue(0x8 | lane.GetLane()); break; case S16: if ((lane.GetLane() & 3) != lane.GetLane()) { return; } SetEncodingValue(0x1 | (lane.GetLane() << 1)); break; case U8: if ((lane.GetLane() & 7) != lane.GetLane()) { return; } SetEncodingValue(0x18 | lane.GetLane()); break; case U16: if ((lane.GetLane() & 3) != lane.GetLane()) { return; } SetEncodingValue(0x11 | (lane.GetLane() << 1)); break; case Untyped32: if ((lane.GetLane() & 1) != lane.GetLane()) { return; } SetEncodingValue(0x0 | (lane.GetLane() << 2)); break; case kDataTypeValueNone: if ((lane.GetLane() & 1) != lane.GetLane()) { return; } SetEncodingValue(0x0 | (lane.GetLane() << 2)); break; default: break; } } class Dt_opc1_opc2_1 : public EncodingValue { public: explicit Dt_opc1_opc2_1(DataType dt, const DRegisterLane& lane); }; Dt_opc1_opc2_1::Dt_opc1_opc2_1(DataType dt, const DRegisterLane& lane) { switch (dt.GetValue()) { case Untyped8: if ((lane.GetLane() & 7) != lane.GetLane()) { return; } SetEncodingValue(0x8 | lane.GetLane()); break; case Untyped16: if ((lane.GetLane() & 3) != lane.GetLane()) { return; } SetEncodingValue(0x1 | (lane.GetLane() << 1)); break; case Untyped32: if ((lane.GetLane() & 1) != lane.GetLane()) { return; } SetEncodingValue(0x0 | (lane.GetLane() << 2)); break; case kDataTypeValueNone: if ((lane.GetLane() & 1) != lane.GetLane()) { return; } SetEncodingValue(0x0 | (lane.GetLane() << 2)); break; default: break; } } class Dt_imm4_1 : public EncodingValue { public: explicit Dt_imm4_1(DataType dt, const DRegisterLane& lane); }; Dt_imm4_1::Dt_imm4_1(DataType dt, const DRegisterLane& lane) { switch (dt.GetValue()) { case Untyped8: if ((lane.GetLane() & 7) != lane.GetLane()) { return; } SetEncodingValue(0x1 | (lane.GetLane() << 1)); break; case Untyped16: if ((lane.GetLane() & 3) != lane.GetLane()) { return; } SetEncodingValue(0x2 | (lane.GetLane() << 2)); break; case Untyped32: if ((lane.GetLane() & 1) != lane.GetLane()) { return; } SetEncodingValue(0x4 | (lane.GetLane() << 3)); break; default: break; } } class Dt_B_E_1 : public EncodingValue { public: explicit Dt_B_E_1(DataType dt); }; Dt_B_E_1::Dt_B_E_1(DataType dt) { switch (dt.GetValue()) { case Untyped8: SetEncodingValue(0x2); break; case Untyped16: SetEncodingValue(0x1); break; case Untyped32: SetEncodingValue(0x0); break; default: break; } } class Dt_op_1 : public EncodingValue { public: Dt_op_1(DataType dt1, DataType dt2); }; Dt_op_1::Dt_op_1(DataType dt1, DataType dt2) { if ((dt1.GetValue() == F32) && (dt2.GetValue() == S32)) { SetEncodingValue(0x0); return; } if ((dt1.GetValue() == F32) && (dt2.GetValue() == U32)) { SetEncodingValue(0x1); return; } if ((dt1.GetValue() == S32) && (dt2.GetValue() == F32)) { SetEncodingValue(0x2); return; } if ((dt1.GetValue() == U32) && (dt2.GetValue() == F32)) { SetEncodingValue(0x3); return; } } class Dt_op_2 : public EncodingValue { public: explicit Dt_op_2(DataType dt); }; Dt_op_2::Dt_op_2(DataType dt) { switch (dt.GetValue()) { case U32: SetEncodingValue(0x0); break; case S32: SetEncodingValue(0x1); break; default: break; } } class Dt_op_3 : public EncodingValue { public: explicit Dt_op_3(DataType dt); }; Dt_op_3::Dt_op_3(DataType dt) { switch (dt.GetValue()) { case S32: SetEncodingValue(0x0); break; case U32: SetEncodingValue(0x1); break; default: break; } } class Dt_U_sx_1 : public EncodingValue { public: explicit Dt_U_sx_1(DataType dt); }; Dt_U_sx_1::Dt_U_sx_1(DataType dt) { switch (dt.GetValue()) { case S16: SetEncodingValue(0x0); break; case S32: SetEncodingValue(0x1); break; case U16: SetEncodingValue(0x2); break; case U32: SetEncodingValue(0x3); break; default: break; } } class Dt_op_U_1 : public EncodingValue { public: Dt_op_U_1(DataType dt1, DataType dt2); }; Dt_op_U_1::Dt_op_U_1(DataType dt1, DataType dt2) { if ((dt1.GetValue() == F32) && (dt2.GetValue() == S32)) { SetEncodingValue(0x0); return; } if ((dt1.GetValue() == F32) && (dt2.GetValue() == U32)) { SetEncodingValue(0x1); return; } if ((dt1.GetValue() == S32) && (dt2.GetValue() == F32)) { SetEncodingValue(0x2); return; } if ((dt1.GetValue() == U32) && (dt2.GetValue() == F32)) { SetEncodingValue(0x3); return; } } class Dt_sz_1 : public EncodingValue { public: explicit Dt_sz_1(DataType dt); }; Dt_sz_1::Dt_sz_1(DataType dt) { switch (dt.GetValue()) { case F32: SetEncodingValue(0x0); break; default: break; } } class Dt_F_size_1 : public EncodingValue { public: explicit Dt_F_size_1(DataType dt); }; Dt_F_size_1::Dt_F_size_1(DataType dt) { switch (dt.GetValue()) { case S8: SetEncodingValue(0x0); break; case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; case F32: SetEncodingValue(0x6); break; default: break; } } class Dt_F_size_2 : public EncodingValue { public: explicit Dt_F_size_2(DataType dt); }; Dt_F_size_2::Dt_F_size_2(DataType dt) { switch (dt.GetValue()) { case I8: SetEncodingValue(0x0); break; case I16: SetEncodingValue(0x1); break; case I32: SetEncodingValue(0x2); break; case F32: SetEncodingValue(0x6); break; default: break; } } class Dt_F_size_3 : public EncodingValue { public: explicit Dt_F_size_3(DataType dt); }; Dt_F_size_3::Dt_F_size_3(DataType dt) { switch (dt.GetValue()) { case I16: SetEncodingValue(0x1); break; case I32: SetEncodingValue(0x2); break; case F32: SetEncodingValue(0x6); break; default: break; } } class Dt_F_size_4 : public EncodingValue { public: explicit Dt_F_size_4(DataType dt); }; Dt_F_size_4::Dt_F_size_4(DataType dt) { switch (dt.GetValue()) { case U32: SetEncodingValue(0x2); break; case F32: SetEncodingValue(0x6); break; default: break; } } class Dt_U_size_1 : public EncodingValue { public: explicit Dt_U_size_1(DataType dt); }; Dt_U_size_1::Dt_U_size_1(DataType dt) { switch (dt.GetValue()) { case S8: SetEncodingValue(0x0); break; case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; case U8: SetEncodingValue(0x4); break; case U16: SetEncodingValue(0x5); break; case U32: SetEncodingValue(0x6); break; default: break; } } class Dt_U_size_2 : public EncodingValue { public: explicit Dt_U_size_2(DataType dt); }; Dt_U_size_2::Dt_U_size_2(DataType dt) { switch (dt.GetValue()) { case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; case U16: SetEncodingValue(0x5); break; case U32: SetEncodingValue(0x6); break; default: break; } } class Dt_U_size_3 : public EncodingValue { public: explicit Dt_U_size_3(DataType dt); }; Dt_U_size_3::Dt_U_size_3(DataType dt) { switch (dt.GetValue()) { case S8: SetEncodingValue(0x0); break; case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; case S64: SetEncodingValue(0x3); break; case U8: SetEncodingValue(0x4); break; case U16: SetEncodingValue(0x5); break; case U32: SetEncodingValue(0x6); break; case U64: SetEncodingValue(0x7); break; default: break; } } class Dt_size_1 : public EncodingValue { public: explicit Dt_size_1(DataType dt); }; Dt_size_1::Dt_size_1(DataType dt) { switch (dt.GetValue()) { case Untyped8: SetEncodingValue(0x0); break; default: break; } } class Dt_size_2 : public EncodingValue { public: explicit Dt_size_2(DataType dt); }; Dt_size_2::Dt_size_2(DataType dt) { switch (dt.GetValue()) { case I8: SetEncodingValue(0x0); break; case I16: SetEncodingValue(0x1); break; case I32: SetEncodingValue(0x2); break; case I64: SetEncodingValue(0x3); break; default: break; } } class Dt_size_3 : public EncodingValue { public: explicit Dt_size_3(DataType dt); }; Dt_size_3::Dt_size_3(DataType dt) { switch (dt.GetValue()) { case I16: SetEncodingValue(0x0); break; case I32: SetEncodingValue(0x1); break; case I64: SetEncodingValue(0x2); break; default: break; } } class Dt_size_4 : public EncodingValue { public: explicit Dt_size_4(DataType dt); }; Dt_size_4::Dt_size_4(DataType dt) { switch (dt.GetValue()) { case I8: SetEncodingValue(0x0); break; case I16: SetEncodingValue(0x1); break; case I32: SetEncodingValue(0x2); break; default: break; } } class Dt_size_5 : public EncodingValue { public: explicit Dt_size_5(DataType dt); }; Dt_size_5::Dt_size_5(DataType dt) { switch (dt.GetValue()) { case S8: SetEncodingValue(0x0); break; case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; default: break; } } class Dt_size_6 : public EncodingValue { public: explicit Dt_size_6(DataType dt); }; Dt_size_6::Dt_size_6(DataType dt) { switch (dt.GetValue()) { case Untyped8: SetEncodingValue(0x0); break; case Untyped16: SetEncodingValue(0x1); break; case Untyped32: SetEncodingValue(0x2); break; case Untyped64: SetEncodingValue(0x3); break; default: break; } } class Dt_size_7 : public EncodingValue { public: explicit Dt_size_7(DataType dt); }; Dt_size_7::Dt_size_7(DataType dt) { switch (dt.GetValue()) { case Untyped8: SetEncodingValue(0x0); break; case Untyped16: SetEncodingValue(0x1); break; case Untyped32: SetEncodingValue(0x2); break; default: break; } } class Dt_size_8 : public EncodingValue { public: Dt_size_8(DataType dt, Alignment align); }; Dt_size_8::Dt_size_8(DataType dt, Alignment align) { switch (dt.GetValue()) { case Untyped8: SetEncodingValue(0x0); break; case Untyped16: SetEncodingValue(0x1); break; case Untyped32: if (align.Is(k64BitAlign) || align.Is(kNoAlignment)) { SetEncodingValue(0x2); } else if (align.Is(k128BitAlign)) { SetEncodingValue(0x3); } break; default: break; } } class Dt_size_9 : public EncodingValue { uint32_t type_; public: explicit Dt_size_9(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_size_9::Dt_size_9(DataType dt) { switch (dt.GetValue()) { case I16: type_ = 0x0; SetEncodingValue(0x1); break; case I32: type_ = 0x0; SetEncodingValue(0x2); break; case F32: type_ = 0x1; SetEncodingValue(0x2); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_size_10 : public EncodingValue { public: explicit Dt_size_10(DataType dt); }; Dt_size_10::Dt_size_10(DataType dt) { switch (dt.GetValue()) { case S8: case U8: case I8: SetEncodingValue(0x0); break; case S16: case U16: case I16: SetEncodingValue(0x1); break; case S32: case U32: case I32: SetEncodingValue(0x2); break; default: break; } } class Dt_size_11 : public EncodingValue { uint32_t type_; public: explicit Dt_size_11(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_size_11::Dt_size_11(DataType dt) { switch (dt.GetValue()) { case S16: type_ = 0x0; SetEncodingValue(0x1); break; case U16: type_ = 0x1; SetEncodingValue(0x1); break; case S32: type_ = 0x0; SetEncodingValue(0x2); break; case U32: type_ = 0x1; SetEncodingValue(0x2); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_size_12 : public EncodingValue { uint32_t type_; public: explicit Dt_size_12(DataType dt); uint32_t GetTypeEncodingValue() const { return type_; } }; Dt_size_12::Dt_size_12(DataType dt) { switch (dt.GetValue()) { case S8: type_ = 0x0; SetEncodingValue(0x0); break; case U8: type_ = 0x1; SetEncodingValue(0x0); break; case S16: type_ = 0x0; SetEncodingValue(0x1); break; case U16: type_ = 0x1; SetEncodingValue(0x1); break; case S32: type_ = 0x0; SetEncodingValue(0x2); break; case U32: type_ = 0x1; SetEncodingValue(0x2); break; default: VIXL_UNREACHABLE(); type_ = 0x0; break; } } class Dt_size_13 : public EncodingValue { public: explicit Dt_size_13(DataType dt); }; Dt_size_13::Dt_size_13(DataType dt) { switch (dt.GetValue()) { case S16: SetEncodingValue(0x1); break; case S32: SetEncodingValue(0x2); break; default: break; } } class Dt_size_14 : public EncodingValue { public: explicit Dt_size_14(DataType dt); }; Dt_size_14::Dt_size_14(DataType dt) { switch (dt.GetValue()) { case S16: SetEncodingValue(0x0); break; case S32: SetEncodingValue(0x1); break; case S64: SetEncodingValue(0x2); break; default: break; } } class Dt_size_15 : public EncodingValue { public: explicit Dt_size_15(DataType dt); }; Dt_size_15::Dt_size_15(DataType dt) { switch (dt.GetValue()) { case Untyped8: SetEncodingValue(0x0); break; case Untyped16: SetEncodingValue(0x1); break; default: break; } } class Dt_size_16 : public EncodingValue { public: explicit Dt_size_16(DataType dt); }; Dt_size_16::Dt_size_16(DataType dt) { switch (dt.GetValue()) { case I8: SetEncodingValue(0x0); break; case I16: SetEncodingValue(0x1); break; case I32: SetEncodingValue(0x2); break; default: break; } } class Index_1 : public EncodingValue { public: Index_1(const NeonRegisterList& nreglist, DataType dt); }; Index_1::Index_1(const NeonRegisterList& nreglist, DataType dt) { switch (dt.GetValue()) { case Untyped8: { if ((nreglist.GetTransferLane() & 7) != nreglist.GetTransferLane()) { return; } uint32_t value = nreglist.GetTransferLane() << 1; if (!nreglist.IsSingleSpaced()) return; SetEncodingValue(value); break; } case Untyped16: { if ((nreglist.GetTransferLane() & 3) != nreglist.GetTransferLane()) { return; } uint32_t value = nreglist.GetTransferLane() << 2; if (nreglist.IsDoubleSpaced()) value |= 2; SetEncodingValue(value); break; } case Untyped32: { if ((nreglist.GetTransferLane() & 1) != nreglist.GetTransferLane()) { return; } uint32_t value = nreglist.GetTransferLane() << 3; if (nreglist.IsDoubleSpaced()) value |= 4; SetEncodingValue(value); break; } default: break; } } class Align_index_align_1 : public EncodingValue { public: Align_index_align_1(Alignment align, const NeonRegisterList& nreglist, DataType dt); }; Align_index_align_1::Align_index_align_1(Alignment align, const NeonRegisterList& nreglist, DataType dt) { switch (dt.GetValue()) { case Untyped8: { uint32_t value; if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 7) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 1; SetEncodingValue(value); break; } case Untyped16: { uint32_t value; if (align.GetType() == k16BitAlign) { value = 1; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 3) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 2; SetEncodingValue(value); break; } case Untyped32: { uint32_t value; if (align.GetType() == k32BitAlign) { value = 3; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 1) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 3; SetEncodingValue(value); break; } default: break; } } class Align_index_align_2 : public EncodingValue { public: Align_index_align_2(Alignment align, const NeonRegisterList& nreglist, DataType dt); }; Align_index_align_2::Align_index_align_2(Alignment align, const NeonRegisterList& nreglist, DataType dt) { switch (dt.GetValue()) { case Untyped8: { uint32_t value; if (align.GetType() == k16BitAlign) { value = 1; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 7) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 1; if (!nreglist.IsSingleSpaced()) return; SetEncodingValue(value); break; } case Untyped16: { uint32_t value; if (align.GetType() == k32BitAlign) { value = 1; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 3) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 2; if (nreglist.IsDoubleSpaced()) value |= 2; SetEncodingValue(value); break; } case Untyped32: { uint32_t value; if (align.GetType() == k64BitAlign) { value = 1; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 1) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 3; if (nreglist.IsDoubleSpaced()) value |= 4; SetEncodingValue(value); break; } default: break; } } class Align_index_align_3 : public EncodingValue { public: Align_index_align_3(Alignment align, const NeonRegisterList& nreglist, DataType dt); }; Align_index_align_3::Align_index_align_3(Alignment align, const NeonRegisterList& nreglist, DataType dt) { switch (dt.GetValue()) { case Untyped8: { uint32_t value; if (align.GetType() == k32BitAlign) { value = 1; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 7) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 1; if (!nreglist.IsSingleSpaced()) return; SetEncodingValue(value); break; } case Untyped16: { uint32_t value; if (align.GetType() == k64BitAlign) { value = 1; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 3) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 2; if (nreglist.IsDoubleSpaced()) value |= 2; SetEncodingValue(value); break; } case Untyped32: { uint32_t value; if (align.GetType() == k64BitAlign) { value = 1; } else if (align.GetType() == k128BitAlign) { value = 2; } else if (align.GetType() == kNoAlignment) { value = 0; } else { return; } if ((nreglist.GetTransferLane() & 1) != nreglist.GetTransferLane()) { return; } value |= nreglist.GetTransferLane() << 3; if (nreglist.IsDoubleSpaced()) value |= 4; SetEncodingValue(value); break; } default: break; } } class Align_a_1 : public EncodingValue { public: Align_a_1(Alignment align, DataType dt); }; Align_a_1::Align_a_1(Alignment align, DataType dt) { switch (align.GetType()) { case k16BitAlign: if (dt.Is(Untyped16)) SetEncodingValue(0x1); break; case k32BitAlign: if (dt.Is(Untyped32)) SetEncodingValue(0x1); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } class Align_a_2 : public EncodingValue { public: Align_a_2(Alignment align, DataType dt); }; Align_a_2::Align_a_2(Alignment align, DataType dt) { switch (align.GetType()) { case k16BitAlign: if (dt.Is(Untyped8)) SetEncodingValue(0x1); break; case k32BitAlign: if (dt.Is(Untyped16)) SetEncodingValue(0x1); break; case k64BitAlign: if (dt.Is(Untyped32)) SetEncodingValue(0x1); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } class Align_a_3 : public EncodingValue { public: Align_a_3(Alignment align, DataType dt); }; Align_a_3::Align_a_3(Alignment align, DataType dt) { switch (align.GetType()) { case k32BitAlign: if (dt.Is(Untyped8)) SetEncodingValue(0x1); break; case k64BitAlign: if (dt.Is(Untyped16)) SetEncodingValue(0x1); else if (dt.Is(Untyped32)) SetEncodingValue(0x1); break; case k128BitAlign: if (dt.Is(Untyped32)) SetEncodingValue(0x1); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } class Align_align_1 : public EncodingValue { public: Align_align_1(Alignment align, const NeonRegisterList& nreglist); }; Align_align_1::Align_align_1(Alignment align, const NeonRegisterList& nreglist) { switch (align.GetType()) { case k64BitAlign: SetEncodingValue(0x1); break; case k128BitAlign: if ((nreglist.GetLength() == 2) || (nreglist.GetLength() == 4)) SetEncodingValue(0x2); break; case k256BitAlign: if ((nreglist.GetLength() == 2) || (nreglist.GetLength() == 4)) SetEncodingValue(0x3); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } class Align_align_2 : public EncodingValue { public: Align_align_2(Alignment align, const NeonRegisterList& nreglist); }; Align_align_2::Align_align_2(Alignment align, const NeonRegisterList& nreglist) { switch (align.GetType()) { case k64BitAlign: SetEncodingValue(0x1); break; case k128BitAlign: SetEncodingValue(0x2); break; case k256BitAlign: if ((nreglist.GetLength() == 4)) SetEncodingValue(0x3); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } class Align_align_3 : public EncodingValue { public: explicit Align_align_3(Alignment align); }; Align_align_3::Align_align_3(Alignment align) { switch (align.GetType()) { case k64BitAlign: SetEncodingValue(0x1); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } class Align_align_4 : public EncodingValue { public: explicit Align_align_4(Alignment align); }; Align_align_4::Align_align_4(Alignment align) { switch (align.GetType()) { case k64BitAlign: SetEncodingValue(0x1); break; case k128BitAlign: SetEncodingValue(0x2); break; case k256BitAlign: SetEncodingValue(0x3); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } class Align_align_5 : public EncodingValue { public: Align_align_5(Alignment align, const NeonRegisterList& nreglist); }; Align_align_5::Align_align_5(Alignment align, const NeonRegisterList& nreglist) { switch (align.GetType()) { case k64BitAlign: SetEncodingValue(0x1); break; case k128BitAlign: if ((nreglist.GetLength() == 2) || (nreglist.GetLength() == 4)) SetEncodingValue(0x2); break; case k256BitAlign: if ((nreglist.GetLength() == 4)) SetEncodingValue(0x3); break; case kNoAlignment: SetEncodingValue(0x0); break; default: break; } } void Assembler::adc(Condition cond, EncodingSize size, Register rd, Register rn, const Operand& operand) { VIXL_ASSERT(AllowAssembler()); CheckIT(cond); if (operand.IsImmediate()) { uint32_t imm = operand.GetImmediate(); if (IsUsingT32()) { ImmediateT32 immediate_t32(imm); // ADC{}{} {}, , # ; T1 if (!size.IsNarrow() && immediate_t32.IsValid() && ((!rd.IsPC() && !rn.IsPC()) || AllowUnpredictable())) { EmitT32_32(0xf1400000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | (immediate_t32.GetEncodingValue() & 0xff) | ((immediate_t32.GetEncodingValue() & 0x700) << 4) | ((immediate_t32.GetEncodingValue() & 0x800) << 15)); AdvanceIT(); return; } } else { ImmediateA32 immediate_a32(imm); // ADC{}{} {}, , # ; A1 if (immediate_a32.IsValid() && cond.IsNotNever()) { EmitA32(0x02a00000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | immediate_a32.GetEncodingValue()); return; } } } if (operand.IsImmediateShiftedRegister()) { Register rm = operand.GetBaseRegister(); if (operand.IsPlainRegister()) { if (IsUsingT32()) { // ADC{} {}, , ; T1 if (InITBlock() && !size.IsWide() && rd.Is(rn) && rn.IsLow() && rm.IsLow()) { EmitT32_16(0x4140 | rd.GetCode() | (rm.GetCode() << 3)); AdvanceIT(); return; } } } Shift shift = operand.GetShift(); uint32_t amount = operand.GetShiftAmount(); if (IsUsingT32()) { // ADC{}{} {}, , {, # } ; T2 if (!size.IsNarrow() && shift.IsValidAmount(amount) && ((!rd.IsPC() && !rn.IsPC() && !rm.IsPC()) || AllowUnpredictable())) { uint32_t amount_ = amount % 32; EmitT32_32(0xeb400000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 4) | ((amount_ & 0x3) << 6) | ((amount_ & 0x1c) << 10)); AdvanceIT(); return; } } else { // ADC{}{} {}, , {, # } ; A1 if (shift.IsValidAmount(amount) && cond.IsNotNever()) { uint32_t amount_ = amount % 32; EmitA32(0x00a00000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 5) | (amount_ << 7)); return; } } } if (operand.IsRegisterShiftedRegister()) { Register rm = operand.GetBaseRegister(); Shift shift = operand.GetShift(); if (IsUsingA32()) { // ADC{}{} {}, , , ; A1 if (cond.IsNotNever() && ((!rd.IsPC() && !rn.IsPC() && !rm.IsPC() && !operand.GetShiftRegister().IsPC()) || AllowUnpredictable())) { EmitA32(0x00a00010U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (shift.GetType() << 5) | (operand.GetShiftRegister().GetCode() << 8)); return; } } } Delegate(kAdc, &Assembler::adc, cond, size, rd, rn, operand); } void Assembler::adcs(Condition cond, EncodingSize size, Register rd, Register rn, const Operand& operand) { VIXL_ASSERT(AllowAssembler()); CheckIT(cond); if (operand.IsImmediate()) { uint32_t imm = operand.GetImmediate(); if (IsUsingT32()) { ImmediateT32 immediate_t32(imm); // ADCS{}{} {}, , # ; T1 if (!size.IsNarrow() && immediate_t32.IsValid() && ((!rd.IsPC() && !rn.IsPC()) || AllowUnpredictable())) { EmitT32_32(0xf1500000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | (immediate_t32.GetEncodingValue() & 0xff) | ((immediate_t32.GetEncodingValue() & 0x700) << 4) | ((immediate_t32.GetEncodingValue() & 0x800) << 15)); AdvanceIT(); return; } } else { ImmediateA32 immediate_a32(imm); // ADCS{}{} {}, , # ; A1 if (immediate_a32.IsValid() && cond.IsNotNever()) { EmitA32(0x02b00000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | immediate_a32.GetEncodingValue()); return; } } } if (operand.IsImmediateShiftedRegister()) { Register rm = operand.GetBaseRegister(); if (operand.IsPlainRegister()) { if (IsUsingT32()) { // ADCS{} {}, , ; T1 if (OutsideITBlock() && !size.IsWide() && rd.Is(rn) && rn.IsLow() && rm.IsLow()) { EmitT32_16(0x4140 | rd.GetCode() | (rm.GetCode() << 3)); AdvanceIT(); return; } } } Shift shift = operand.GetShift(); uint32_t amount = operand.GetShiftAmount(); if (IsUsingT32()) { // ADCS{}{} {}, , {, # } ; T2 if (!size.IsNarrow() && shift.IsValidAmount(amount) && ((!rd.IsPC() && !rn.IsPC() && !rm.IsPC()) || AllowUnpredictable())) { uint32_t amount_ = amount % 32; EmitT32_32(0xeb500000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 4) | ((amount_ & 0x3) << 6) | ((amount_ & 0x1c) << 10)); AdvanceIT(); return; } } else { // ADCS{}{} {}, , {, # } ; A1 if (shift.IsValidAmount(amount) && cond.IsNotNever()) { uint32_t amount_ = amount % 32; EmitA32(0x00b00000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 5) | (amount_ << 7)); return; } } } if (operand.IsRegisterShiftedRegister()) { Register rm = operand.GetBaseRegister(); Shift shift = operand.GetShift(); if (IsUsingA32()) { // ADCS{}{} {}, , , ; A1 if (cond.IsNotNever() && ((!rd.IsPC() && !rn.IsPC() && !rm.IsPC() && !operand.GetShiftRegister().IsPC()) || AllowUnpredictable())) { EmitA32(0x00b00010U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (shift.GetType() << 5) | (operand.GetShiftRegister().GetCode() << 8)); return; } } } Delegate(kAdcs, &Assembler::adcs, cond, size, rd, rn, operand); } void Assembler::add(Condition cond, EncodingSize size, Register rd, Register rn, const Operand& operand) { VIXL_ASSERT(AllowAssembler()); CheckIT(cond); if (operand.IsImmediate()) { uint32_t imm = operand.GetImmediate(); if (IsUsingT32()) { ImmediateT32 immediate_t32(imm); // ADD{}{} , PC, # ; T1 if (!size.IsWide() && rd.IsLow() && rn.Is(pc) && (imm <= 1020) && ((imm % 4) == 0)) { uint32_t imm_ = imm >> 2; EmitT32_16(0xa000 | (rd.GetCode() << 8) | imm_); AdvanceIT(); return; } // ADD{} , , # ; T1 if (InITBlock() && !size.IsWide() && rd.IsLow() && rn.IsLow() && (imm <= 7)) { EmitT32_16(0x1c00 | rd.GetCode() | (rn.GetCode() << 3) | (imm << 6)); AdvanceIT(); return; } // ADD{} {}, , # ; T2 if (InITBlock() && !size.IsWide() && rd.Is(rn) && rn.IsLow() && (imm <= 255)) { EmitT32_16(0x3000 | (rd.GetCode() << 8) | imm); AdvanceIT(); return; } // ADD{}{} , SP, # ; T1 if (!size.IsWide() && rd.IsLow() && rn.Is(sp) && (imm <= 1020) && ((imm % 4) == 0)) { uint32_t imm_ = imm >> 2; EmitT32_16(0xa800 | (rd.GetCode() << 8) | imm_); AdvanceIT(); return; } // ADD{}{} {SP}, SP, # ; T2 if (!size.IsWide() && rd.Is(sp) && rn.Is(sp) && (imm <= 508) && ((imm % 4) == 0)) { uint32_t imm_ = imm >> 2; EmitT32_16(0xb000 | imm_); AdvanceIT(); return; } // ADD{}{} , PC, # ; T3 if (!size.IsNarrow() && rn.Is(pc) && (imm <= 4095) && (!rd.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf20f0000U | (rd.GetCode() << 8) | (imm & 0xff) | ((imm & 0x700) << 4) | ((imm & 0x800) << 15)); AdvanceIT(); return; } // ADD{}{} {}, , # ; T3 if (!size.IsNarrow() && immediate_t32.IsValid() && !rn.Is(sp) && ((!rd.IsPC() && !rn.IsPC()) || AllowUnpredictable())) { EmitT32_32(0xf1000000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | (immediate_t32.GetEncodingValue() & 0xff) | ((immediate_t32.GetEncodingValue() & 0x700) << 4) | ((immediate_t32.GetEncodingValue() & 0x800) << 15)); AdvanceIT(); return; } // ADD{}{} {}, , # ; T4 if (!size.IsNarrow() && (imm <= 4095) && ((rn.GetCode() & 0xd) != 0xd) && (!rd.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf2000000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | (imm & 0xff) | ((imm & 0x700) << 4) | ((imm & 0x800) << 15)); AdvanceIT(); return; } // ADD{}{} {}, SP, # ; T3 if (!size.IsNarrow() && rn.Is(sp) && immediate_t32.IsValid() && (!rd.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf10d0000U | (rd.GetCode() << 8) | (immediate_t32.GetEncodingValue() & 0xff) | ((immediate_t32.GetEncodingValue() & 0x700) << 4) | ((immediate_t32.GetEncodingValue() & 0x800) << 15)); AdvanceIT(); return; } // ADD{}{} {}, SP, # ; T4 if (!size.IsNarrow() && rn.Is(sp) && (imm <= 4095) && (!rd.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf20d0000U | (rd.GetCode() << 8) | (imm & 0xff) | ((imm & 0x700) << 4) | ((imm & 0x800) << 15)); AdvanceIT(); return; } } else { ImmediateA32 immediate_a32(imm); // ADD{}{} , PC, # ; A1 if (rn.Is(pc) && immediate_a32.IsValid() && cond.IsNotNever()) { EmitA32(0x028f0000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | immediate_a32.GetEncodingValue()); return; } // ADD{}{} {}, , # ; A1 if (immediate_a32.IsValid() && cond.IsNotNever() && ((rn.GetCode() & 0xd) != 0xd)) { EmitA32(0x02800000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | immediate_a32.GetEncodingValue()); return; } // ADD{}{} {}, SP, # ; A1 if (rn.Is(sp) && immediate_a32.IsValid() && cond.IsNotNever()) { EmitA32(0x028d0000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | immediate_a32.GetEncodingValue()); return; } } } if (operand.IsImmediateShiftedRegister()) { Register rm = operand.GetBaseRegister(); if (operand.IsPlainRegister()) { if (IsUsingT32()) { // ADD{} , , ; T1 if (InITBlock() && !size.IsWide() && rd.IsLow() && rn.IsLow() && rm.IsLow()) { EmitT32_16(0x1800 | rd.GetCode() | (rn.GetCode() << 3) | (rm.GetCode() << 6)); AdvanceIT(); return; } // ADD{}{} {}, , ; T2 if (!size.IsWide() && rd.Is(rn) && !rm.Is(sp) && (((!rd.IsPC() || OutsideITBlockAndAlOrLast(cond)) && (!rd.IsPC() || !rm.IsPC())) || AllowUnpredictable())) { EmitT32_16(0x4400 | (rd.GetCode() & 0x7) | ((rd.GetCode() & 0x8) << 4) | (rm.GetCode() << 3)); AdvanceIT(); return; } // ADD{}{} {}, SP, ; T1 if (!size.IsWide() && rd.Is(rm) && rn.Is(sp) && ((!rd.IsPC() || OutsideITBlockAndAlOrLast(cond)) || AllowUnpredictable())) { EmitT32_16(0x4468 | (rd.GetCode() & 0x7) | ((rd.GetCode() & 0x8) << 4)); AdvanceIT(); return; } // ADD{}{} {SP}, SP, ; T2 if (!size.IsWide() && rd.Is(sp) && rn.Is(sp) && !rm.Is(sp)) { EmitT32_16(0x4485 | (rm.GetCode() << 3)); AdvanceIT(); return; } } } Shift shift = operand.GetShift(); uint32_t amount = operand.GetShiftAmount(); if (IsUsingT32()) { // ADD{}{} {}, , {, # } ; T3 if (!size.IsNarrow() && shift.IsValidAmount(amount) && !rn.Is(sp) && ((!rd.IsPC() && !rn.IsPC() && !rm.IsPC()) || AllowUnpredictable())) { uint32_t amount_ = amount % 32; EmitT32_32(0xeb000000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 4) | ((amount_ & 0x3) << 6) | ((amount_ & 0x1c) << 10)); AdvanceIT(); return; } // ADD{}{} {}, SP, {, # } ; T3 if (!size.IsNarrow() && rn.Is(sp) && shift.IsValidAmount(amount) && ((!rd.IsPC() && !rm.IsPC()) || AllowUnpredictable())) { uint32_t amount_ = amount % 32; EmitT32_32(0xeb0d0000U | (rd.GetCode() << 8) | rm.GetCode() | (operand.GetTypeEncodingValue() << 4) | ((amount_ & 0x3) << 6) | ((amount_ & 0x1c) << 10)); AdvanceIT(); return; } } else { // ADD{}{} {}, , {, # } ; A1 if (shift.IsValidAmount(amount) && cond.IsNotNever() && !rn.Is(sp)) { uint32_t amount_ = amount % 32; EmitA32(0x00800000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 5) | (amount_ << 7)); return; } // ADD{}{} {}, SP, {, # } ; A1 if (rn.Is(sp) && shift.IsValidAmount(amount) && cond.IsNotNever()) { uint32_t amount_ = amount % 32; EmitA32(0x008d0000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | rm.GetCode() | (operand.GetTypeEncodingValue() << 5) | (amount_ << 7)); return; } } } if (operand.IsRegisterShiftedRegister()) { Register rm = operand.GetBaseRegister(); Shift shift = operand.GetShift(); if (IsUsingA32()) { // ADD{}{} {}, , , ; A1 if (cond.IsNotNever() && ((!rd.IsPC() && !rn.IsPC() && !rm.IsPC() && !operand.GetShiftRegister().IsPC()) || AllowUnpredictable())) { EmitA32(0x00800010U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (shift.GetType() << 5) | (operand.GetShiftRegister().GetCode() << 8)); return; } } } Delegate(kAdd, &Assembler::add, cond, size, rd, rn, operand); } void Assembler::add(Condition cond, Register rd, const Operand& operand) { VIXL_ASSERT(AllowAssembler()); CheckIT(cond); if (operand.IsImmediate()) { uint32_t imm = operand.GetImmediate(); if (IsUsingT32()) { // ADD{} , # ; T2 if (InITBlock() && rd.IsLow() && (imm <= 255)) { EmitT32_16(0x3000 | (rd.GetCode() << 8) | imm); AdvanceIT(); return; } } } if (operand.IsPlainRegister()) { Register rm = operand.GetBaseRegister(); if (IsUsingT32()) { // ADD{} , ; T2 if (InITBlock() && !rm.Is(sp) && (((!rd.IsPC() || OutsideITBlockAndAlOrLast(cond)) && (!rd.IsPC() || !rm.IsPC())) || AllowUnpredictable())) { EmitT32_16(0x4400 | (rd.GetCode() & 0x7) | ((rd.GetCode() & 0x8) << 4) | (rm.GetCode() << 3)); AdvanceIT(); return; } } } Delegate(kAdd, &Assembler::add, cond, rd, operand); } void Assembler::adds(Condition cond, EncodingSize size, Register rd, Register rn, const Operand& operand) { VIXL_ASSERT(AllowAssembler()); CheckIT(cond); if (operand.IsImmediate()) { uint32_t imm = operand.GetImmediate(); if (IsUsingT32()) { ImmediateT32 immediate_t32(imm); // ADDS{} , , # ; T1 if (OutsideITBlock() && !size.IsWide() && rd.IsLow() && rn.IsLow() && (imm <= 7)) { EmitT32_16(0x1c00 | rd.GetCode() | (rn.GetCode() << 3) | (imm << 6)); AdvanceIT(); return; } // ADDS{} {}, , # ; T2 if (OutsideITBlock() && !size.IsWide() && rd.Is(rn) && rn.IsLow() && (imm <= 255)) { EmitT32_16(0x3000 | (rd.GetCode() << 8) | imm); AdvanceIT(); return; } // ADDS{}{} {}, , # ; T3 if (!size.IsNarrow() && immediate_t32.IsValid() && !rn.Is(sp) && !rd.Is(pc) && (!rn.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf1100000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | (immediate_t32.GetEncodingValue() & 0xff) | ((immediate_t32.GetEncodingValue() & 0x700) << 4) | ((immediate_t32.GetEncodingValue() & 0x800) << 15)); AdvanceIT(); return; } // ADDS{}{} {}, SP, # ; T3 if (!size.IsNarrow() && rn.Is(sp) && immediate_t32.IsValid() && !rd.Is(pc)) { EmitT32_32(0xf11d0000U | (rd.GetCode() << 8) | (immediate_t32.GetEncodingValue() & 0xff) | ((immediate_t32.GetEncodingValue() & 0x700) << 4) | ((immediate_t32.GetEncodingValue() & 0x800) << 15)); AdvanceIT(); return; } } else { ImmediateA32 immediate_a32(imm); // ADDS{}{} {}, , # ; A1 if (immediate_a32.IsValid() && cond.IsNotNever() && !rn.Is(sp)) { EmitA32(0x02900000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | immediate_a32.GetEncodingValue()); return; } // ADDS{}{} {}, SP, # ; A1 if (rn.Is(sp) && immediate_a32.IsValid() && cond.IsNotNever()) { EmitA32(0x029d0000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | immediate_a32.GetEncodingValue()); return; } } } if (operand.IsImmediateShiftedRegister()) { Register rm = operand.GetBaseRegister(); if (operand.IsPlainRegister()) { if (IsUsingT32()) { // ADDS{} {}, , ; T1 if (OutsideITBlock() && !size.IsWide() && rd.IsLow() && rn.IsLow() && rm.IsLow()) { EmitT32_16(0x1800 | rd.GetCode() | (rn.GetCode() << 3) | (rm.GetCode() << 6)); AdvanceIT(); return; } } } Shift shift = operand.GetShift(); uint32_t amount = operand.GetShiftAmount(); if (IsUsingT32()) { // ADDS{}{} {}, , {, # } ; T3 if (!size.IsNarrow() && shift.IsValidAmount(amount) && !rn.Is(sp) && !rd.Is(pc) && ((!rn.IsPC() && !rm.IsPC()) || AllowUnpredictable())) { uint32_t amount_ = amount % 32; EmitT32_32(0xeb100000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 4) | ((amount_ & 0x3) << 6) | ((amount_ & 0x1c) << 10)); AdvanceIT(); return; } // ADDS{}{} {}, SP, {, # } ; T3 if (!size.IsNarrow() && rn.Is(sp) && shift.IsValidAmount(amount) && !rd.Is(pc) && (!rm.IsPC() || AllowUnpredictable())) { uint32_t amount_ = amount % 32; EmitT32_32(0xeb1d0000U | (rd.GetCode() << 8) | rm.GetCode() | (operand.GetTypeEncodingValue() << 4) | ((amount_ & 0x3) << 6) | ((amount_ & 0x1c) << 10)); AdvanceIT(); return; } } else { // ADDS{}{} {}, , {, # } ; A1 if (shift.IsValidAmount(amount) && cond.IsNotNever() && !rn.Is(sp)) { uint32_t amount_ = amount % 32; EmitA32(0x00900000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (operand.GetTypeEncodingValue() << 5) | (amount_ << 7)); return; } // ADDS{}{} {}, SP, {, # } ; A1 if (rn.Is(sp) && shift.IsValidAmount(amount) && cond.IsNotNever()) { uint32_t amount_ = amount % 32; EmitA32(0x009d0000U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | rm.GetCode() | (operand.GetTypeEncodingValue() << 5) | (amount_ << 7)); return; } } } if (operand.IsRegisterShiftedRegister()) { Register rm = operand.GetBaseRegister(); Shift shift = operand.GetShift(); if (IsUsingA32()) { // ADDS{}{} {}, , , ; A1 if (cond.IsNotNever() && ((!rd.IsPC() && !rn.IsPC() && !rm.IsPC() && !operand.GetShiftRegister().IsPC()) || AllowUnpredictable())) { EmitA32(0x00900010U | (cond.GetCondition() << 28) | (rd.GetCode() << 12) | (rn.GetCode() << 16) | rm.GetCode() | (shift.GetType() << 5) | (operand.GetShiftRegister().GetCode() << 8)); return; } } } Delegate(kAdds, &Assembler::adds, cond, size, rd, rn, operand); } void Assembler::adds(Register rd, const Operand& operand) { VIXL_ASSERT(AllowAssembler()); CheckIT(al); if (operand.IsImmediate()) { uint32_t imm = operand.GetImmediate(); if (IsUsingT32()) { // ADDS{} , # ; T2 if (OutsideITBlock() && rd.IsLow() && (imm <= 255)) { EmitT32_16(0x3000 | (rd.GetCode() << 8) | imm); AdvanceIT(); return; } } } Delegate(kAdds, &Assembler::adds, rd, operand); } void Assembler::addw(Condition cond, Register rd, Register rn, const Operand& operand) { VIXL_ASSERT(AllowAssembler()); CheckIT(cond); if (operand.IsImmediate()) { uint32_t imm = operand.GetImmediate(); if (IsUsingT32()) { // ADDW{}{} , PC, # ; T3 if (rn.Is(pc) && (imm <= 4095) && (!rd.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf20f0000U | (rd.GetCode() << 8) | (imm & 0xff) | ((imm & 0x700) << 4) | ((imm & 0x800) << 15)); AdvanceIT(); return; } // ADDW{}{} {}, , # ; T4 if ((imm <= 4095) && ((rn.GetCode() & 0xd) != 0xd) && (!rd.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf2000000U | (rd.GetCode() << 8) | (rn.GetCode() << 16) | (imm & 0xff) | ((imm & 0x700) << 4) | ((imm & 0x800) << 15)); AdvanceIT(); return; } // ADDW{}{} {}, SP, # ; T4 if (rn.Is(sp) && (imm <= 4095) && (!rd.IsPC() || AllowUnpredictable())) { EmitT32_32(0xf20d0000U | (rd.GetCode() << 8) | (imm & 0xff) | ((imm & 0x700) << 4) | ((imm & 0x800) << 15)); AdvanceIT(); return; } } } Delegate(kAddw, &Assembler::addw, cond, rd, rn, operand); } void Assembler::adr(Condition cond, EncodingSize size, Register rd, Label* label) { VIXL_ASSERT(AllowAssembler()); CheckIT(cond); Label::Offset offset = label->IsBound() ? label->GetLocation() - AlignDown(GetCursorOffset() + GetArchitectureStatePCOffset(), 4) : 0; if (IsUsingT32()) { int32_t neg_offset = -offset; // ADR{}{} ,