dep: Add vixl (AArch32/64 assembler)

This commit is contained in:
Connor McLaughlin
2019-12-04 20:11:06 +10:00
parent baaa94d4c1
commit d520ca35eb
61 changed files with 178153 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,855 @@
// Copyright 2016, 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.
#include "aarch32/constants-aarch32.h"
#include "utils-vixl.h"
namespace vixl {
namespace aarch32 {
// Start of generated code.
const char* ToCString(InstructionType type) {
switch (type) {
case kAdc:
return "adc";
case kAdcs:
return "adcs";
case kAdd:
return "add";
case kAdds:
return "adds";
case kAddw:
return "addw";
case kAdr:
return "adr";
case kAnd:
return "and";
case kAnds:
return "ands";
case kAsr:
return "asr";
case kAsrs:
return "asrs";
case kB:
return "b";
case kBfc:
return "bfc";
case kBfi:
return "bfi";
case kBic:
return "bic";
case kBics:
return "bics";
case kBkpt:
return "bkpt";
case kBl:
return "bl";
case kBlx:
return "blx";
case kBx:
return "bx";
case kBxj:
return "bxj";
case kCbnz:
return "cbnz";
case kCbz:
return "cbz";
case kClrex:
return "clrex";
case kClz:
return "clz";
case kCmn:
return "cmn";
case kCmp:
return "cmp";
case kCrc32b:
return "crc32b";
case kCrc32cb:
return "crc32cb";
case kCrc32ch:
return "crc32ch";
case kCrc32cw:
return "crc32cw";
case kCrc32h:
return "crc32h";
case kCrc32w:
return "crc32w";
case kDmb:
return "dmb";
case kDsb:
return "dsb";
case kEor:
return "eor";
case kEors:
return "eors";
case kFldmdbx:
return "fldmdbx";
case kFldmiax:
return "fldmiax";
case kFstmdbx:
return "fstmdbx";
case kFstmiax:
return "fstmiax";
case kHlt:
return "hlt";
case kHvc:
return "hvc";
case kIsb:
return "isb";
case kIt:
return "it";
case kLda:
return "lda";
case kLdab:
return "ldab";
case kLdaex:
return "ldaex";
case kLdaexb:
return "ldaexb";
case kLdaexd:
return "ldaexd";
case kLdaexh:
return "ldaexh";
case kLdah:
return "ldah";
case kLdm:
return "ldm";
case kLdmda:
return "ldmda";
case kLdmdb:
return "ldmdb";
case kLdmea:
return "ldmea";
case kLdmed:
return "ldmed";
case kLdmfa:
return "ldmfa";
case kLdmfd:
return "ldmfd";
case kLdmib:
return "ldmib";
case kLdr:
return "ldr";
case kLdrb:
return "ldrb";
case kLdrd:
return "ldrd";
case kLdrex:
return "ldrex";
case kLdrexb:
return "ldrexb";
case kLdrexd:
return "ldrexd";
case kLdrexh:
return "ldrexh";
case kLdrh:
return "ldrh";
case kLdrsb:
return "ldrsb";
case kLdrsh:
return "ldrsh";
case kLsl:
return "lsl";
case kLsls:
return "lsls";
case kLsr:
return "lsr";
case kLsrs:
return "lsrs";
case kMla:
return "mla";
case kMlas:
return "mlas";
case kMls:
return "mls";
case kMov:
return "mov";
case kMovs:
return "movs";
case kMovt:
return "movt";
case kMovw:
return "movw";
case kMrs:
return "mrs";
case kMsr:
return "msr";
case kMul:
return "mul";
case kMuls:
return "muls";
case kMvn:
return "mvn";
case kMvns:
return "mvns";
case kNop:
return "nop";
case kOrn:
return "orn";
case kOrns:
return "orns";
case kOrr:
return "orr";
case kOrrs:
return "orrs";
case kPkhbt:
return "pkhbt";
case kPkhtb:
return "pkhtb";
case kPld:
return "pld";
case kPldw:
return "pldw";
case kPli:
return "pli";
case kPop:
return "pop";
case kPush:
return "push";
case kQadd:
return "qadd";
case kQadd16:
return "qadd16";
case kQadd8:
return "qadd8";
case kQasx:
return "qasx";
case kQdadd:
return "qdadd";
case kQdsub:
return "qdsub";
case kQsax:
return "qsax";
case kQsub:
return "qsub";
case kQsub16:
return "qsub16";
case kQsub8:
return "qsub8";
case kRbit:
return "rbit";
case kRev:
return "rev";
case kRev16:
return "rev16";
case kRevsh:
return "revsh";
case kRor:
return "ror";
case kRors:
return "rors";
case kRrx:
return "rrx";
case kRrxs:
return "rrxs";
case kRsb:
return "rsb";
case kRsbs:
return "rsbs";
case kRsc:
return "rsc";
case kRscs:
return "rscs";
case kSadd16:
return "sadd16";
case kSadd8:
return "sadd8";
case kSasx:
return "sasx";
case kSbc:
return "sbc";
case kSbcs:
return "sbcs";
case kSbfx:
return "sbfx";
case kSdiv:
return "sdiv";
case kSel:
return "sel";
case kShadd16:
return "shadd16";
case kShadd8:
return "shadd8";
case kShasx:
return "shasx";
case kShsax:
return "shsax";
case kShsub16:
return "shsub16";
case kShsub8:
return "shsub8";
case kSmlabb:
return "smlabb";
case kSmlabt:
return "smlabt";
case kSmlad:
return "smlad";
case kSmladx:
return "smladx";
case kSmlal:
return "smlal";
case kSmlalbb:
return "smlalbb";
case kSmlalbt:
return "smlalbt";
case kSmlald:
return "smlald";
case kSmlaldx:
return "smlaldx";
case kSmlals:
return "smlals";
case kSmlaltb:
return "smlaltb";
case kSmlaltt:
return "smlaltt";
case kSmlatb:
return "smlatb";
case kSmlatt:
return "smlatt";
case kSmlawb:
return "smlawb";
case kSmlawt:
return "smlawt";
case kSmlsd:
return "smlsd";
case kSmlsdx:
return "smlsdx";
case kSmlsld:
return "smlsld";
case kSmlsldx:
return "smlsldx";
case kSmmla:
return "smmla";
case kSmmlar:
return "smmlar";
case kSmmls:
return "smmls";
case kSmmlsr:
return "smmlsr";
case kSmmul:
return "smmul";
case kSmmulr:
return "smmulr";
case kSmuad:
return "smuad";
case kSmuadx:
return "smuadx";
case kSmulbb:
return "smulbb";
case kSmulbt:
return "smulbt";
case kSmull:
return "smull";
case kSmulls:
return "smulls";
case kSmultb:
return "smultb";
case kSmultt:
return "smultt";
case kSmulwb:
return "smulwb";
case kSmulwt:
return "smulwt";
case kSmusd:
return "smusd";
case kSmusdx:
return "smusdx";
case kSsat:
return "ssat";
case kSsat16:
return "ssat16";
case kSsax:
return "ssax";
case kSsub16:
return "ssub16";
case kSsub8:
return "ssub8";
case kStl:
return "stl";
case kStlb:
return "stlb";
case kStlex:
return "stlex";
case kStlexb:
return "stlexb";
case kStlexd:
return "stlexd";
case kStlexh:
return "stlexh";
case kStlh:
return "stlh";
case kStm:
return "stm";
case kStmda:
return "stmda";
case kStmdb:
return "stmdb";
case kStmea:
return "stmea";
case kStmed:
return "stmed";
case kStmfa:
return "stmfa";
case kStmfd:
return "stmfd";
case kStmib:
return "stmib";
case kStr:
return "str";
case kStrb:
return "strb";
case kStrd:
return "strd";
case kStrex:
return "strex";
case kStrexb:
return "strexb";
case kStrexd:
return "strexd";
case kStrexh:
return "strexh";
case kStrh:
return "strh";
case kSub:
return "sub";
case kSubs:
return "subs";
case kSubw:
return "subw";
case kSvc:
return "svc";
case kSxtab:
return "sxtab";
case kSxtab16:
return "sxtab16";
case kSxtah:
return "sxtah";
case kSxtb:
return "sxtb";
case kSxtb16:
return "sxtb16";
case kSxth:
return "sxth";
case kTbb:
return "tbb";
case kTbh:
return "tbh";
case kTeq:
return "teq";
case kTst:
return "tst";
case kUadd16:
return "uadd16";
case kUadd8:
return "uadd8";
case kUasx:
return "uasx";
case kUbfx:
return "ubfx";
case kUdf:
return "udf";
case kUdiv:
return "udiv";
case kUhadd16:
return "uhadd16";
case kUhadd8:
return "uhadd8";
case kUhasx:
return "uhasx";
case kUhsax:
return "uhsax";
case kUhsub16:
return "uhsub16";
case kUhsub8:
return "uhsub8";
case kUmaal:
return "umaal";
case kUmlal:
return "umlal";
case kUmlals:
return "umlals";
case kUmull:
return "umull";
case kUmulls:
return "umulls";
case kUqadd16:
return "uqadd16";
case kUqadd8:
return "uqadd8";
case kUqasx:
return "uqasx";
case kUqsax:
return "uqsax";
case kUqsub16:
return "uqsub16";
case kUqsub8:
return "uqsub8";
case kUsad8:
return "usad8";
case kUsada8:
return "usada8";
case kUsat:
return "usat";
case kUsat16:
return "usat16";
case kUsax:
return "usax";
case kUsub16:
return "usub16";
case kUsub8:
return "usub8";
case kUxtab:
return "uxtab";
case kUxtab16:
return "uxtab16";
case kUxtah:
return "uxtah";
case kUxtb:
return "uxtb";
case kUxtb16:
return "uxtb16";
case kUxth:
return "uxth";
case kVaba:
return "vaba";
case kVabal:
return "vabal";
case kVabd:
return "vabd";
case kVabdl:
return "vabdl";
case kVabs:
return "vabs";
case kVacge:
return "vacge";
case kVacgt:
return "vacgt";
case kVacle:
return "vacle";
case kVaclt:
return "vaclt";
case kVadd:
return "vadd";
case kVaddhn:
return "vaddhn";
case kVaddl:
return "vaddl";
case kVaddw:
return "vaddw";
case kVand:
return "vand";
case kVbic:
return "vbic";
case kVbif:
return "vbif";
case kVbit:
return "vbit";
case kVbsl:
return "vbsl";
case kVceq:
return "vceq";
case kVcge:
return "vcge";
case kVcgt:
return "vcgt";
case kVcle:
return "vcle";
case kVcls:
return "vcls";
case kVclt:
return "vclt";
case kVclz:
return "vclz";
case kVcmp:
return "vcmp";
case kVcmpe:
return "vcmpe";
case kVcnt:
return "vcnt";
case kVcvt:
return "vcvt";
case kVcvta:
return "vcvta";
case kVcvtb:
return "vcvtb";
case kVcvtm:
return "vcvtm";
case kVcvtn:
return "vcvtn";
case kVcvtp:
return "vcvtp";
case kVcvtr:
return "vcvtr";
case kVcvtt:
return "vcvtt";
case kVdiv:
return "vdiv";
case kVdup:
return "vdup";
case kVeor:
return "veor";
case kVext:
return "vext";
case kVfma:
return "vfma";
case kVfms:
return "vfms";
case kVfnma:
return "vfnma";
case kVfnms:
return "vfnms";
case kVhadd:
return "vhadd";
case kVhsub:
return "vhsub";
case kVld1:
return "vld1";
case kVld2:
return "vld2";
case kVld3:
return "vld3";
case kVld4:
return "vld4";
case kVldm:
return "vldm";
case kVldmdb:
return "vldmdb";
case kVldmia:
return "vldmia";
case kVldr:
return "vldr";
case kVmax:
return "vmax";
case kVmaxnm:
return "vmaxnm";
case kVmin:
return "vmin";
case kVminnm:
return "vminnm";
case kVmla:
return "vmla";
case kVmlal:
return "vmlal";
case kVmls:
return "vmls";
case kVmlsl:
return "vmlsl";
case kVmov:
return "vmov";
case kVmovl:
return "vmovl";
case kVmovn:
return "vmovn";
case kVmrs:
return "vmrs";
case kVmsr:
return "vmsr";
case kVmul:
return "vmul";
case kVmull:
return "vmull";
case kVmvn:
return "vmvn";
case kVneg:
return "vneg";
case kVnmla:
return "vnmla";
case kVnmls:
return "vnmls";
case kVnmul:
return "vnmul";
case kVorn:
return "vorn";
case kVorr:
return "vorr";
case kVpadal:
return "vpadal";
case kVpadd:
return "vpadd";
case kVpaddl:
return "vpaddl";
case kVpmax:
return "vpmax";
case kVpmin:
return "vpmin";
case kVpop:
return "vpop";
case kVpush:
return "vpush";
case kVqabs:
return "vqabs";
case kVqadd:
return "vqadd";
case kVqdmlal:
return "vqdmlal";
case kVqdmlsl:
return "vqdmlsl";
case kVqdmulh:
return "vqdmulh";
case kVqdmull:
return "vqdmull";
case kVqmovn:
return "vqmovn";
case kVqmovun:
return "vqmovun";
case kVqneg:
return "vqneg";
case kVqrdmulh:
return "vqrdmulh";
case kVqrshl:
return "vqrshl";
case kVqrshrn:
return "vqrshrn";
case kVqrshrun:
return "vqrshrun";
case kVqshl:
return "vqshl";
case kVqshlu:
return "vqshlu";
case kVqshrn:
return "vqshrn";
case kVqshrun:
return "vqshrun";
case kVqsub:
return "vqsub";
case kVraddhn:
return "vraddhn";
case kVrecpe:
return "vrecpe";
case kVrecps:
return "vrecps";
case kVrev16:
return "vrev16";
case kVrev32:
return "vrev32";
case kVrev64:
return "vrev64";
case kVrhadd:
return "vrhadd";
case kVrinta:
return "vrinta";
case kVrintm:
return "vrintm";
case kVrintn:
return "vrintn";
case kVrintp:
return "vrintp";
case kVrintr:
return "vrintr";
case kVrintx:
return "vrintx";
case kVrintz:
return "vrintz";
case kVrshl:
return "vrshl";
case kVrshr:
return "vrshr";
case kVrshrn:
return "vrshrn";
case kVrsqrte:
return "vrsqrte";
case kVrsqrts:
return "vrsqrts";
case kVrsra:
return "vrsra";
case kVrsubhn:
return "vrsubhn";
case kVseleq:
return "vseleq";
case kVselge:
return "vselge";
case kVselgt:
return "vselgt";
case kVselvs:
return "vselvs";
case kVshl:
return "vshl";
case kVshll:
return "vshll";
case kVshr:
return "vshr";
case kVshrn:
return "vshrn";
case kVsli:
return "vsli";
case kVsqrt:
return "vsqrt";
case kVsra:
return "vsra";
case kVsri:
return "vsri";
case kVst1:
return "vst1";
case kVst2:
return "vst2";
case kVst3:
return "vst3";
case kVst4:
return "vst4";
case kVstm:
return "vstm";
case kVstmdb:
return "vstmdb";
case kVstmia:
return "vstmia";
case kVstr:
return "vstr";
case kVsub:
return "vsub";
case kVsubhn:
return "vsubhn";
case kVsubl:
return "vsubl";
case kVsubw:
return "vsubw";
case kVswp:
return "vswp";
case kVtbl:
return "vtbl";
case kVtbx:
return "vtbx";
case kVtrn:
return "vtrn";
case kVtst:
return "vtst";
case kVuzp:
return "vuzp";
case kVzip:
return "vzip";
case kYield:
return "yield";
case kUndefInstructionType:
VIXL_UNREACHABLE();
return "";
}
VIXL_UNREACHABLE();
return "";
} // NOLINT(readability/fn_size)
// End of generated code.
} // namespace aarch32
} // namespace vixl

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,742 @@
// Copyright 2017, 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 <stdint.h>
}
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include "utils-vixl.h"
#include "aarch32/constants-aarch32.h"
#include "aarch32/instructions-aarch32.h"
namespace vixl {
namespace aarch32 {
bool Shift::IsValidAmount(uint32_t amount) const {
switch (GetType()) {
case LSL:
return amount <= 31;
case ROR:
return (amount > 0) && (amount <= 31);
case LSR:
case ASR:
return (amount > 0) && (amount <= 32);
case RRX:
return amount == 0;
default:
VIXL_UNREACHABLE();
return false;
}
}
std::ostream& operator<<(std::ostream& os, const Register reg) {
switch (reg.GetCode()) {
case 12:
return os << "ip";
case 13:
return os << "sp";
case 14:
return os << "lr";
case 15:
return os << "pc";
default:
return os << "r" << reg.GetCode();
}
}
SRegister VRegister::S() const {
VIXL_ASSERT(GetType() == kSRegister);
return SRegister(GetCode());
}
DRegister VRegister::D() const {
VIXL_ASSERT(GetType() == kDRegister);
return DRegister(GetCode());
}
QRegister VRegister::Q() const {
VIXL_ASSERT(GetType() == kQRegister);
return QRegister(GetCode());
}
Register RegisterList::GetFirstAvailableRegister() const {
for (uint32_t i = 0; i < kNumberOfRegisters; i++) {
if (((list_ >> i) & 1) != 0) return Register(i);
}
return Register();
}
std::ostream& PrintRegisterList(std::ostream& os, // NOLINT(runtime/references)
uint32_t list) {
os << "{";
bool first = true;
int code = 0;
while (list != 0) {
if ((list & 1) != 0) {
if (first) {
first = false;
} else {
os << ",";
}
os << Register(code);
}
list >>= 1;
code++;
}
os << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, RegisterList registers) {
return PrintRegisterList(os, registers.GetList());
}
QRegister VRegisterList::GetFirstAvailableQRegister() const {
for (uint32_t i = 0; i < kNumberOfQRegisters; i++) {
if (((list_ >> (i * 4)) & 0xf) == 0xf) return QRegister(i);
}
return QRegister();
}
DRegister VRegisterList::GetFirstAvailableDRegister() const {
for (uint32_t i = 0; i < kMaxNumberOfDRegisters; i++) {
if (((list_ >> (i * 2)) & 0x3) == 0x3) return DRegister(i);
}
return DRegister();
}
SRegister VRegisterList::GetFirstAvailableSRegister() const {
for (uint32_t i = 0; i < kNumberOfSRegisters; i++) {
if (((list_ >> i) & 0x1) != 0) return SRegister(i);
}
return SRegister();
}
std::ostream& operator<<(std::ostream& os, SRegisterList reglist) {
SRegister first = reglist.GetFirstSRegister();
SRegister last = reglist.GetLastSRegister();
if (first.Is(last))
os << "{" << first << "}";
else
os << "{" << first << "-" << last << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, DRegisterList reglist) {
DRegister first = reglist.GetFirstDRegister();
DRegister last = reglist.GetLastDRegister();
if (first.Is(last))
os << "{" << first << "}";
else
os << "{" << first << "-" << last << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, NeonRegisterList nreglist) {
DRegister first = nreglist.GetFirstDRegister();
int increment = nreglist.IsSingleSpaced() ? 1 : 2;
int count =
nreglist.GetLastDRegister().GetCode() - first.GetCode() + increment;
if (count < 0) count += kMaxNumberOfDRegisters;
os << "{";
bool first_displayed = false;
for (;;) {
if (first_displayed) {
os << ",";
} else {
first_displayed = true;
}
os << first;
if (nreglist.IsTransferOneLane()) {
os << "[" << nreglist.GetTransferLane() << "]";
} else if (nreglist.IsTransferAllLanes()) {
os << "[]";
}
count -= increment;
if (count <= 0) break;
unsigned next = first.GetCode() + increment;
if (next >= kMaxNumberOfDRegisters) next -= kMaxNumberOfDRegisters;
first = DRegister(next);
}
os << "}";
return os;
}
const char* SpecialRegister::GetName() const {
switch (reg_) {
case APSR:
return "APSR";
case SPSR:
return "SPSR";
}
VIXL_UNREACHABLE();
return "??";
}
const char* MaskedSpecialRegister::GetName() const {
switch (reg_) {
case APSR_nzcvq:
return "APSR_nzcvq";
case APSR_g:
return "APSR_g";
case APSR_nzcvqg:
return "APSR_nzcvqg";
case CPSR_c:
return "CPSR_c";
case CPSR_x:
return "CPSR_x";
case CPSR_xc:
return "CPSR_xc";
case CPSR_sc:
return "CPSR_sc";
case CPSR_sx:
return "CPSR_sx";
case CPSR_sxc:
return "CPSR_sxc";
case CPSR_fc:
return "CPSR_fc";
case CPSR_fx:
return "CPSR_fx";
case CPSR_fxc:
return "CPSR_fxc";
case CPSR_fsc:
return "CPSR_fsc";
case CPSR_fsx:
return "CPSR_fsx";
case CPSR_fsxc:
return "CPSR_fsxc";
case SPSR_c:
return "SPSR_c";
case SPSR_x:
return "SPSR_x";
case SPSR_xc:
return "SPSR_xc";
case SPSR_s:
return "SPSR_s";
case SPSR_sc:
return "SPSR_sc";
case SPSR_sx:
return "SPSR_sx";
case SPSR_sxc:
return "SPSR_sxc";
case SPSR_f:
return "SPSR_f";
case SPSR_fc:
return "SPSR_fc";
case SPSR_fx:
return "SPSR_fx";
case SPSR_fxc:
return "SPSR_fxc";
case SPSR_fs:
return "SPSR_fs";
case SPSR_fsc:
return "SPSR_fsc";
case SPSR_fsx:
return "SPSR_fsx";
case SPSR_fsxc:
return "SPSR_fsxc";
}
VIXL_UNREACHABLE();
return "??";
}
const char* BankedRegister::GetName() const {
switch (reg_) {
case R8_usr:
return "R8_usr";
case R9_usr:
return "R9_usr";
case R10_usr:
return "R10_usr";
case R11_usr:
return "R11_usr";
case R12_usr:
return "R12_usr";
case SP_usr:
return "SP_usr";
case LR_usr:
return "LR_usr";
case R8_fiq:
return "R8_fiq";
case R9_fiq:
return "R9_fiq";
case R10_fiq:
return "R10_fiq";
case R11_fiq:
return "R11_fiq";
case R12_fiq:
return "R12_fiq";
case SP_fiq:
return "SP_fiq";
case LR_fiq:
return "LR_fiq";
case LR_irq:
return "LR_irq";
case SP_irq:
return "SP_irq";
case LR_svc:
return "LR_svc";
case SP_svc:
return "SP_svc";
case LR_abt:
return "LR_abt";
case SP_abt:
return "SP_abt";
case LR_und:
return "LR_und";
case SP_und:
return "SP_und";
case LR_mon:
return "LR_mon";
case SP_mon:
return "SP_mon";
case ELR_hyp:
return "ELR_hyp";
case SP_hyp:
return "SP_hyp";
case SPSR_fiq:
return "SPSR_fiq";
case SPSR_irq:
return "SPSR_irq";
case SPSR_svc:
return "SPSR_svc";
case SPSR_abt:
return "SPSR_abt";
case SPSR_und:
return "SPSR_und";
case SPSR_mon:
return "SPSR_mon";
case SPSR_hyp:
return "SPSR_hyp";
}
VIXL_UNREACHABLE();
return "??";
}
const char* SpecialFPRegister::GetName() const {
switch (reg_) {
case FPSID:
return "FPSID";
case FPSCR:
return "FPSCR";
case MVFR2:
return "MVFR2";
case MVFR1:
return "MVFR1";
case MVFR0:
return "MVFR0";
case FPEXC:
return "FPEXC";
}
VIXL_UNREACHABLE();
return "??";
}
const char* Condition::GetName() const {
switch (condition_) {
case eq:
return "eq";
case ne:
return "ne";
case cs:
return "cs";
case cc:
return "cc";
case mi:
return "mi";
case pl:
return "pl";
case vs:
return "vs";
case vc:
return "vc";
case hi:
return "hi";
case ls:
return "ls";
case ge:
return "ge";
case lt:
return "lt";
case gt:
return "gt";
case le:
return "le";
case al:
return "";
case Condition::kNone:
return "";
}
return "<und>";
}
const char* Shift::GetName() const {
switch (shift_) {
case LSL:
return "lsl";
case LSR:
return "lsr";
case ASR:
return "asr";
case ROR:
return "ror";
case RRX:
return "rrx";
}
VIXL_UNREACHABLE();
return "??";
}
const char* EncodingSize::GetName() const {
switch (size_) {
case Best:
case Narrow:
return "";
case Wide:
return ".w";
}
VIXL_UNREACHABLE();
return "??";
}
const char* DataType::GetName() const {
switch (value_) {
case kDataTypeValueInvalid:
return ".??";
case kDataTypeValueNone:
return "";
case S8:
return ".s8";
case S16:
return ".s16";
case S32:
return ".s32";
case S64:
return ".s64";
case U8:
return ".u8";
case U16:
return ".u16";
case U32:
return ".u32";
case U64:
return ".u64";
case F16:
return ".f16";
case F32:
return ".f32";
case F64:
return ".f64";
case I8:
return ".i8";
case I16:
return ".i16";
case I32:
return ".i32";
case I64:
return ".i64";
case P8:
return ".p8";
case P64:
return ".p64";
case Untyped8:
return ".8";
case Untyped16:
return ".16";
case Untyped32:
return ".32";
case Untyped64:
return ".64";
}
VIXL_UNREACHABLE();
return ".??";
}
const char* MemoryBarrier::GetName() const {
switch (type_) {
case OSHLD:
return "oshld";
case OSHST:
return "oshst";
case OSH:
return "osh";
case NSHLD:
return "nshld";
case NSHST:
return "nshst";
case NSH:
return "nsh";
case ISHLD:
return "ishld";
case ISHST:
return "ishst";
case ISH:
return "ish";
case LD:
return "ld";
case ST:
return "st";
case SY:
return "sy";
}
switch (static_cast<int>(type_)) {
case 0:
return "#0x0";
case 4:
return "#0x4";
case 8:
return "#0x8";
case 0xc:
return "#0xc";
}
VIXL_UNREACHABLE();
return "??";
}
const char* InterruptFlags::GetName() const {
switch (type_) {
case F:
return "f";
case I:
return "i";
case IF:
return "if";
case A:
return "a";
case AF:
return "af";
case AI:
return "ai";
case AIF:
return "aif";
}
VIXL_ASSERT(type_ == 0);
return "";
}
const char* Endianness::GetName() const {
switch (type_) {
case LE:
return "le";
case BE:
return "be";
}
VIXL_UNREACHABLE();
return "??";
}
// Constructor used for disassembly.
ImmediateShiftOperand::ImmediateShiftOperand(int shift_value, int amount_value)
: Shift(shift_value) {
switch (shift_value) {
case LSL:
amount_ = amount_value;
break;
case LSR:
case ASR:
amount_ = (amount_value == 0) ? 32 : amount_value;
break;
case ROR:
amount_ = amount_value;
if (amount_value == 0) SetType(RRX);
break;
default:
VIXL_UNREACHABLE();
SetType(LSL);
amount_ = 0;
break;
}
}
ImmediateT32::ImmediateT32(uint32_t imm) {
// 00000000 00000000 00000000 abcdefgh
if ((imm & ~0xff) == 0) {
SetEncodingValue(imm);
return;
}
if ((imm >> 16) == (imm & 0xffff)) {
if ((imm & 0xff00) == 0) {
// 00000000 abcdefgh 00000000 abcdefgh
SetEncodingValue((imm & 0xff) | (0x1 << 8));
return;
}
if ((imm & 0xff) == 0) {
// abcdefgh 00000000 abcdefgh 00000000
SetEncodingValue(((imm >> 8) & 0xff) | (0x2 << 8));
return;
}
if (((imm >> 8) & 0xff) == (imm & 0xff)) {
// abcdefgh abcdefgh abcdefgh abcdefgh
SetEncodingValue((imm & 0xff) | (0x3 << 8));
return;
}
}
for (int shift = 0; shift < 24; shift++) {
uint32_t imm8 = imm >> (24 - shift);
uint32_t overflow = imm << (8 + shift);
if ((imm8 <= 0xff) && ((imm8 & 0x80) != 0) && (overflow == 0)) {
SetEncodingValue(((shift + 8) << 7) | (imm8 & 0x7F));
return;
}
}
}
static inline uint32_t ror(uint32_t x, int i) {
VIXL_ASSERT((0 < i) && (i < 32));
return (x >> i) | (x << (32 - i));
}
bool ImmediateT32::IsImmediateT32(uint32_t imm) {
/* abcdefgh abcdefgh abcdefgh abcdefgh */
if ((imm ^ ror(imm, 8)) == 0) return true;
/* 00000000 abcdefgh 00000000 abcdefgh */
/* abcdefgh 00000000 abcdefgh 00000000 */
if ((imm ^ ror(imm, 16)) == 0 &&
(((imm & 0xff00) == 0) || ((imm & 0xff) == 0)))
return true;
/* isolate least-significant set bit */
uint32_t lsb = imm & -imm;
/* if imm is less than lsb*256 then it fits, but instead we test imm/256 to
* avoid overflow (underflow is always a successful case) */
return ((imm >> 8) < lsb);
}
uint32_t ImmediateT32::Decode(uint32_t value) {
uint32_t base = value & 0xff;
switch (value >> 8) {
case 0:
return base;
case 1:
return base | (base << 16);
case 2:
return (base << 8) | (base << 24);
case 3:
return base | (base << 8) | (base << 16) | (base << 24);
default:
base |= 0x80;
return base << (32 - (value >> 7));
}
}
ImmediateA32::ImmediateA32(uint32_t imm) {
// Deal with rot = 0 first to avoid undefined shift by 32.
if (imm <= 0xff) {
SetEncodingValue(imm);
return;
}
for (int rot = 2; rot < 32; rot += 2) {
uint32_t imm8 = (imm << rot) | (imm >> (32 - rot));
if (imm8 <= 0xff) {
SetEncodingValue((rot << 7) | imm8);
return;
}
}
}
bool ImmediateA32::IsImmediateA32(uint32_t imm) {
/* fast-out */
if (imm < 256) return true;
/* avoid getting confused by wrapped-around bytes (this transform has no
* effect on pass/fail results) */
if (imm & 0xff000000) imm = ror(imm, 16);
/* copy odd-numbered set bits into even-numbered bits immediately below, so
* that the least-significant set bit is always an even bit */
imm = imm | ((imm >> 1) & 0x55555555);
/* isolate least-significant set bit (always even) */
uint32_t lsb = imm & -imm;
/* if imm is less than lsb*256 then it fits, but instead we test imm/256 to
* avoid overflow (underflow is always a successful case) */
return ((imm >> 8) < lsb);
}
uint32_t ImmediateA32::Decode(uint32_t value) {
int rotation = (value >> 8) * 2;
VIXL_ASSERT(rotation >= 0);
VIXL_ASSERT(rotation <= 30);
value &= 0xff;
if (rotation == 0) return value;
return (value >> rotation) | (value << (32 - rotation));
}
uint32_t TypeEncodingValue(Shift shift) {
return shift.IsRRX() ? kRRXEncodedValue : shift.GetValue();
}
uint32_t AmountEncodingValue(Shift shift, uint32_t amount) {
switch (shift.GetType()) {
case LSL:
case ROR:
return amount;
case LSR:
case ASR:
return amount % 32;
case RRX:
return 0;
}
return 0;
}
} // namespace aarch32
} // namespace vixl

View File

@ -0,0 +1,152 @@
// Copyright 2017, 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.
#include "location-aarch32.h"
#include "assembler-aarch32.h"
#include "macro-assembler-aarch32.h"
namespace vixl {
namespace aarch32 {
bool Location::Needs16BitPadding(int32_t location) const {
if (!HasForwardReferences()) return false;
const ForwardRef& last_ref = GetLastForwardReference();
int32_t min_location_last_ref = last_ref.GetMinLocation();
VIXL_ASSERT(min_location_last_ref - location <= 2);
return (min_location_last_ref > location);
}
void Location::ResolveReferences(internal::AssemblerBase* assembler) {
// Iterate over references and call EncodeLocationFor on each of them.
for (ForwardRefListIterator it(this); !it.Done(); it.Advance()) {
const ForwardRef& reference = *it.Current();
VIXL_ASSERT(reference.LocationIsEncodable(location_));
int32_t from = reference.GetLocation();
EncodeLocationFor(assembler, from, reference.op());
}
forward_.clear();
}
static bool Is16BitEncoding(uint16_t instr) {
return instr < (kLowestT32_32Opcode >> 16);
}
void Location::EncodeLocationFor(internal::AssemblerBase* assembler,
int32_t from,
const Location::EmitOperator* encoder) {
if (encoder->IsUsingT32()) {
uint16_t* instr_ptr =
assembler->GetBuffer()->GetOffsetAddress<uint16_t*>(from);
if (Is16BitEncoding(instr_ptr[0])) {
// The Encode methods always deals with uint32_t types so we need
// to explicitly cast it.
uint32_t instr = static_cast<uint32_t>(instr_ptr[0]);
instr = encoder->Encode(instr, from, this);
// The Encode method should not ever set the top 16 bits.
VIXL_ASSERT((instr & ~0xffff) == 0);
instr_ptr[0] = static_cast<uint16_t>(instr);
} else {
uint32_t instr =
instr_ptr[1] | (static_cast<uint32_t>(instr_ptr[0]) << 16);
instr = encoder->Encode(instr, from, this);
instr_ptr[0] = static_cast<uint16_t>(instr >> 16);
instr_ptr[1] = static_cast<uint16_t>(instr);
}
} else {
uint32_t* instr_ptr =
assembler->GetBuffer()->GetOffsetAddress<uint32_t*>(from);
instr_ptr[0] = encoder->Encode(instr_ptr[0], from, this);
}
}
void Location::AddForwardRef(int32_t instr_location,
const EmitOperator& op,
const ReferenceInfo* info) {
VIXL_ASSERT(referenced_);
int32_t from = instr_location + (op.IsUsingT32() ? kT32PcDelta : kA32PcDelta);
if (info->pc_needs_aligning == ReferenceInfo::kAlignPc)
from = AlignDown(from, 4);
int32_t min_object_location = from + info->min_offset;
int32_t max_object_location = from + info->max_offset;
forward_.insert(ForwardRef(&op,
instr_location,
info->size,
min_object_location,
max_object_location,
info->alignment));
}
int Location::GetMaxAlignment() const {
int max_alignment = GetPoolObjectAlignment();
for (ForwardRefListIterator it(const_cast<Location*>(this)); !it.Done();
it.Advance()) {
const ForwardRef& reference = *it.Current();
if (reference.GetAlignment() > max_alignment)
max_alignment = reference.GetAlignment();
}
return max_alignment;
}
int Location::GetMinLocation() const {
int32_t min_location = 0;
for (ForwardRefListIterator it(const_cast<Location*>(this)); !it.Done();
it.Advance()) {
const ForwardRef& reference = *it.Current();
if (reference.GetMinLocation() > min_location)
min_location = reference.GetMinLocation();
}
return min_location;
}
void Label::UpdatePoolObject(PoolObject<int32_t>* object) {
VIXL_ASSERT(forward_.size() == 1);
const ForwardRef& reference = forward_.Front();
object->Update(reference.GetMinLocation(),
reference.GetMaxLocation(),
reference.GetAlignment());
}
void Label::EmitPoolObject(MacroAssemblerInterface* masm) {
MacroAssembler* macro_assembler = static_cast<MacroAssembler*>(masm);
// Add a new branch to this label.
macro_assembler->GetBuffer()->EnsureSpaceFor(kMaxInstructionSizeInBytes);
ExactAssemblyScopeWithoutPoolsCheck guard(macro_assembler,
kMaxInstructionSizeInBytes,
ExactAssemblyScope::kMaximumSize);
macro_assembler->b(this);
}
void RawLiteral::EmitPoolObject(MacroAssemblerInterface* masm) {
Assembler* assembler = static_cast<Assembler*>(masm->AsAssemblerBase());
assembler->GetBuffer()->EnsureSpaceFor(GetSize());
assembler->GetBuffer()->EmitData(GetDataAddress(), GetSize());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,563 @@
// Copyright 2017, 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 <inttypes.h>
#include <stdint.h>
}
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include "utils-vixl.h"
#include "aarch32/constants-aarch32.h"
#include "aarch32/instructions-aarch32.h"
#include "aarch32/operands-aarch32.h"
namespace vixl {
namespace aarch32 {
// Operand
std::ostream& operator<<(std::ostream& os, const Operand& operand) {
if (operand.IsImmediate()) {
return os << "#" << operand.GetImmediate();
}
if (operand.IsImmediateShiftedRegister()) {
if ((operand.GetShift().IsLSL() || operand.GetShift().IsROR()) &&
(operand.GetShiftAmount() == 0)) {
return os << operand.GetBaseRegister();
}
if (operand.GetShift().IsRRX()) {
return os << operand.GetBaseRegister() << ", rrx";
}
return os << operand.GetBaseRegister() << ", " << operand.GetShift() << " #"
<< operand.GetShiftAmount();
}
if (operand.IsRegisterShiftedRegister()) {
return os << operand.GetBaseRegister() << ", " << operand.GetShift() << " "
<< operand.GetShiftRegister();
}
VIXL_UNREACHABLE();
return os;
}
std::ostream& operator<<(std::ostream& os, const NeonImmediate& neon_imm) {
if (neon_imm.IsDouble()) {
if (neon_imm.imm_.d_ == 0) {
if (copysign(1.0, neon_imm.imm_.d_) < 0.0) {
return os << "#-0.0";
}
return os << "#0.0";
}
return os << "#" << std::setprecision(9) << neon_imm.imm_.d_;
}
if (neon_imm.IsFloat()) {
if (neon_imm.imm_.f_ == 0) {
if (copysign(1.0, neon_imm.imm_.d_) < 0.0) return os << "#-0.0";
return os << "#0.0";
}
return os << "#" << std::setprecision(9) << neon_imm.imm_.f_;
}
if (neon_imm.IsInteger64()) {
return os << "#0x" << std::hex << std::setw(16) << std::setfill('0')
<< neon_imm.imm_.u64_ << std::dec;
}
return os << "#" << neon_imm.imm_.u32_;
}
// SOperand
std::ostream& operator<<(std::ostream& os, const SOperand& operand) {
if (operand.IsImmediate()) {
return os << operand.GetNeonImmediate();
}
return os << operand.GetRegister();
}
// DOperand
std::ostream& operator<<(std::ostream& os, const DOperand& operand) {
if (operand.IsImmediate()) {
return os << operand.GetNeonImmediate();
}
return os << operand.GetRegister();
}
// QOperand
std::ostream& operator<<(std::ostream& os, const QOperand& operand) {
if (operand.IsImmediate()) {
return os << operand.GetNeonImmediate();
}
return os << operand.GetRegister();
}
ImmediateVbic::ImmediateVbic(DataType dt, const NeonImmediate& neon_imm) {
if (neon_imm.IsInteger32()) {
uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
if (dt.GetValue() == I16) {
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x9);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0xb);
SetEncodedImmediate(immediate >> 8);
}
} else if (dt.GetValue() == I32) {
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x1);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0x3);
SetEncodedImmediate(immediate >> 8);
} else if ((immediate & ~0xff0000) == 0) {
SetEncodingValue(0x5);
SetEncodedImmediate(immediate >> 16);
} else if ((immediate & ~0xff000000) == 0) {
SetEncodingValue(0x7);
SetEncodedImmediate(immediate >> 24);
}
}
}
}
DataType ImmediateVbic::DecodeDt(uint32_t cmode) {
switch (cmode) {
case 0x1:
case 0x3:
case 0x5:
case 0x7:
return I32;
case 0x9:
case 0xb:
return I16;
default:
break;
}
VIXL_UNREACHABLE();
return kDataTypeValueInvalid;
}
NeonImmediate ImmediateVbic::DecodeImmediate(uint32_t cmode,
uint32_t immediate) {
switch (cmode) {
case 0x1:
case 0x9:
return immediate;
case 0x3:
case 0xb:
return immediate << 8;
case 0x5:
return immediate << 16;
case 0x7:
return immediate << 24;
default:
break;
}
VIXL_UNREACHABLE();
return 0;
}
ImmediateVmov::ImmediateVmov(DataType dt, const NeonImmediate& neon_imm) {
if (neon_imm.IsInteger()) {
switch (dt.GetValue()) {
case I8:
if (neon_imm.CanConvert<uint8_t>()) {
SetEncodingValue(0xe);
SetEncodedImmediate(neon_imm.GetImmediate<uint8_t>());
}
break;
case I16:
if (neon_imm.IsInteger32()) {
uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x8);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0xa);
SetEncodedImmediate(immediate >> 8);
}
}
break;
case I32:
if (neon_imm.IsInteger32()) {
uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x0);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0x2);
SetEncodedImmediate(immediate >> 8);
} else if ((immediate & ~0xff0000) == 0) {
SetEncodingValue(0x4);
SetEncodedImmediate(immediate >> 16);
} else if ((immediate & ~0xff000000) == 0) {
SetEncodingValue(0x6);
SetEncodedImmediate(immediate >> 24);
} else if ((immediate & ~0xff00) == 0xff) {
SetEncodingValue(0xc);
SetEncodedImmediate(immediate >> 8);
} else if ((immediate & ~0xff0000) == 0xffff) {
SetEncodingValue(0xd);
SetEncodedImmediate(immediate >> 16);
}
}
break;
case I64: {
bool is_valid = true;
uint32_t encoding = 0;
if (neon_imm.IsInteger32()) {
uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
uint32_t mask = 0xff000000;
for (uint32_t set_bit = 1 << 3; set_bit != 0; set_bit >>= 1) {
if ((immediate & mask) == mask) {
encoding |= set_bit;
} else if ((immediate & mask) != 0) {
is_valid = false;
break;
}
mask >>= 8;
}
} else {
uint64_t immediate = neon_imm.GetImmediate<uint64_t>();
uint64_t mask = UINT64_C(0xff) << 56;
for (uint32_t set_bit = 1 << 7; set_bit != 0; set_bit >>= 1) {
if ((immediate & mask) == mask) {
encoding |= set_bit;
} else if ((immediate & mask) != 0) {
is_valid = false;
break;
}
mask >>= 8;
}
}
if (is_valid) {
SetEncodingValue(0x1e);
SetEncodedImmediate(encoding);
}
break;
}
default:
break;
}
} else {
switch (dt.GetValue()) {
case F32:
if (neon_imm.IsFloat() || neon_imm.IsDouble()) {
ImmediateVFP vfp(neon_imm.GetImmediate<float>());
if (vfp.IsValid()) {
SetEncodingValue(0xf);
SetEncodedImmediate(vfp.GetEncodingValue());
}
}
break;
default:
break;
}
}
}
DataType ImmediateVmov::DecodeDt(uint32_t cmode) {
switch (cmode & 0xf) {
case 0x0:
case 0x2:
case 0x4:
case 0x6:
case 0xc:
case 0xd:
return I32;
case 0x8:
case 0xa:
return I16;
case 0xe:
return ((cmode & 0x10) == 0) ? I8 : I64;
case 0xf:
if ((cmode & 0x10) == 0) return F32;
break;
default:
break;
}
VIXL_UNREACHABLE();
return kDataTypeValueInvalid;
}
NeonImmediate ImmediateVmov::DecodeImmediate(uint32_t cmode,
uint32_t immediate) {
switch (cmode & 0xf) {
case 0x8:
case 0x0:
return immediate;
case 0x2:
case 0xa:
return immediate << 8;
case 0x4:
return immediate << 16;
case 0x6:
return immediate << 24;
case 0xc:
return (immediate << 8) | 0xff;
case 0xd:
return (immediate << 16) | 0xffff;
case 0xe: {
if (cmode == 0x1e) {
uint64_t encoding = 0;
for (uint32_t set_bit = 1 << 7; set_bit != 0; set_bit >>= 1) {
encoding <<= 8;
if ((immediate & set_bit) != 0) {
encoding |= 0xff;
}
}
return encoding;
} else {
return immediate;
}
}
case 0xf: {
return ImmediateVFP::Decode<float>(immediate);
}
default:
break;
}
VIXL_UNREACHABLE();
return 0;
}
ImmediateVmvn::ImmediateVmvn(DataType dt, const NeonImmediate& neon_imm) {
if (neon_imm.IsInteger32()) {
uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
switch (dt.GetValue()) {
case I16:
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x8);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0xa);
SetEncodedImmediate(immediate >> 8);
}
break;
case I32:
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x0);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0x2);
SetEncodedImmediate(immediate >> 8);
} else if ((immediate & ~0xff0000) == 0) {
SetEncodingValue(0x4);
SetEncodedImmediate(immediate >> 16);
} else if ((immediate & ~0xff000000) == 0) {
SetEncodingValue(0x6);
SetEncodedImmediate(immediate >> 24);
} else if ((immediate & ~0xff00) == 0xff) {
SetEncodingValue(0xc);
SetEncodedImmediate(immediate >> 8);
} else if ((immediate & ~0xff0000) == 0xffff) {
SetEncodingValue(0xd);
SetEncodedImmediate(immediate >> 16);
}
break;
default:
break;
}
}
}
DataType ImmediateVmvn::DecodeDt(uint32_t cmode) {
switch (cmode) {
case 0x0:
case 0x2:
case 0x4:
case 0x6:
case 0xc:
case 0xd:
return I32;
case 0x8:
case 0xa:
return I16;
default:
break;
}
VIXL_UNREACHABLE();
return kDataTypeValueInvalid;
}
NeonImmediate ImmediateVmvn::DecodeImmediate(uint32_t cmode,
uint32_t immediate) {
switch (cmode) {
case 0x0:
case 0x8:
return immediate;
case 0x2:
case 0xa:
return immediate << 8;
case 0x4:
return immediate << 16;
case 0x6:
return immediate << 24;
case 0xc:
return (immediate << 8) | 0xff;
case 0xd:
return (immediate << 16) | 0xffff;
default:
break;
}
VIXL_UNREACHABLE();
return 0;
}
ImmediateVorr::ImmediateVorr(DataType dt, const NeonImmediate& neon_imm) {
if (neon_imm.IsInteger32()) {
uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
if (dt.GetValue() == I16) {
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x9);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0xb);
SetEncodedImmediate(immediate >> 8);
}
} else if (dt.GetValue() == I32) {
if ((immediate & ~0xff) == 0) {
SetEncodingValue(0x1);
SetEncodedImmediate(immediate);
} else if ((immediate & ~0xff00) == 0) {
SetEncodingValue(0x3);
SetEncodedImmediate(immediate >> 8);
} else if ((immediate & ~0xff0000) == 0) {
SetEncodingValue(0x5);
SetEncodedImmediate(immediate >> 16);
} else if ((immediate & ~0xff000000) == 0) {
SetEncodingValue(0x7);
SetEncodedImmediate(immediate >> 24);
}
}
}
}
DataType ImmediateVorr::DecodeDt(uint32_t cmode) {
switch (cmode) {
case 0x1:
case 0x3:
case 0x5:
case 0x7:
return I32;
case 0x9:
case 0xb:
return I16;
default:
break;
}
VIXL_UNREACHABLE();
return kDataTypeValueInvalid;
}
NeonImmediate ImmediateVorr::DecodeImmediate(uint32_t cmode,
uint32_t immediate) {
switch (cmode) {
case 0x1:
case 0x9:
return immediate;
case 0x3:
case 0xb:
return immediate << 8;
case 0x5:
return immediate << 16;
case 0x7:
return immediate << 24;
default:
break;
}
VIXL_UNREACHABLE();
return 0;
}
// MemOperand
std::ostream& operator<<(std::ostream& os, const MemOperand& operand) {
os << "[" << operand.GetBaseRegister();
if (operand.GetAddrMode() == PostIndex) {
os << "]";
if (operand.IsRegisterOnly()) return os << "!";
}
if (operand.IsImmediate()) {
if ((operand.GetOffsetImmediate() != 0) || operand.GetSign().IsMinus() ||
((operand.GetAddrMode() != Offset) && !operand.IsRegisterOnly())) {
if (operand.GetOffsetImmediate() == 0) {
os << ", #" << operand.GetSign() << operand.GetOffsetImmediate();
} else {
os << ", #" << operand.GetOffsetImmediate();
}
}
} else if (operand.IsPlainRegister()) {
os << ", " << operand.GetSign() << operand.GetOffsetRegister();
} else if (operand.IsShiftedRegister()) {
os << ", " << operand.GetSign() << operand.GetOffsetRegister()
<< ImmediateShiftOperand(operand.GetShift(), operand.GetShiftAmount());
} else {
VIXL_UNREACHABLE();
return os;
}
if (operand.GetAddrMode() == Offset) {
os << "]";
} else if (operand.GetAddrMode() == PreIndex) {
os << "]!";
}
return os;
}
std::ostream& operator<<(std::ostream& os, const AlignedMemOperand& operand) {
os << "[" << operand.GetBaseRegister() << operand.GetAlignment() << "]";
if (operand.GetAddrMode() == PostIndex) {
if (operand.IsPlainRegister()) {
os << ", " << operand.GetOffsetRegister();
} else {
os << "!";
}
}
return os;
}
} // namespace aarch32
} // namespace vixl