| Index: src/IceInstARM32.cpp
|
| diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
|
| index aff4ef335ab2486335468c852a9a51eab7871c24..99584dc010349319244437752d2b19b0ba99b2e3 100644
|
| --- a/src/IceInstARM32.cpp
|
| +++ b/src/IceInstARM32.cpp
|
| @@ -33,7 +33,7 @@ const struct TypeARM32Attributes_ {
|
| int8_t SExtAddrOffsetBits;
|
| int8_t ZExtAddrOffsetBits;
|
| } TypeARM32Attributes[] = {
|
| -#define X(tag, elementty, int_width, vec_width, sbits, ubits) \
|
| +#define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr) \
|
| { int_width, vec_width, sbits, ubits } \
|
| ,
|
| ICETYPEARM32_TABLE
|
| @@ -211,8 +211,6 @@ bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) {
|
| return Offset == 0;
|
| // Note that encodings for offsets are sign-magnitude for ARM, so we check
|
| // with IsAbsoluteUint().
|
| - if (isScalarFloatingType(Ty))
|
| - return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset);
|
| return Utils::IsAbsoluteUint(Bits, Offset);
|
| }
|
|
|
| @@ -392,6 +390,11 @@ InstARM32Vcmp::InstARM32Vcmp(Cfg *Func, Variable *Src0, Variable *Src1,
|
| InstARM32Vmrs::InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate)
|
| : InstARM32Pred(Func, InstARM32::Vmrs, 0, nullptr, Predicate) {}
|
|
|
| +InstARM32Vabs::InstARM32Vabs(Cfg *Func, Variable *Dest, Variable *Src,
|
| + CondARM32::Cond Predicate)
|
| + : InstARM32Pred(Func, InstARM32::Vabs, 1, Dest, Predicate) {
|
| + addSource(Src);
|
| +}
|
| // ======================== Dump routines ======================== //
|
|
|
| // Two-addr ops
|
| @@ -408,9 +411,6 @@ template <> const char *InstARM32Uxt::Opcode = "uxt"; // still requires b/h
|
| template <> const char *InstARM32Vsqrt::Opcode = "vsqrt";
|
| // Mov-like ops
|
| template <> const char *InstARM32Ldr::Opcode = "ldr";
|
| -template <> const char *InstARM32Mov::Opcode = "mov";
|
| -// FP
|
| -template <> const char *InstARM32Vldr::Opcode = "vldr";
|
| // Three-addr ops
|
| template <> const char *InstARM32Adc::Opcode = "adc";
|
| template <> const char *InstARM32Add::Opcode = "add";
|
| @@ -447,113 +447,56 @@ void InstARM32::dump(const Cfg *Func) const {
|
| Inst::dump(Func);
|
| }
|
|
|
| -template <> void InstARM32Mov::emit(const Cfg *Func) const {
|
| - if (!BuildDefs::dump())
|
| - return;
|
| - Ostream &Str = Func->getContext()->getStrEmit();
|
| - assert(getSrcSize() == 1);
|
| - Variable *Dest = getDest();
|
| - if (Dest->hasReg()) {
|
| - IceString ActualOpcode = Opcode;
|
| - Operand *Src0 = getSrc(0);
|
| - if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) {
|
| - if (!Src0V->hasReg()) {
|
| - // Always use the whole stack slot. A 32-bit load has a larger range of
|
| - // offsets than 16-bit, etc.
|
| - ActualOpcode = IceString("ldr");
|
| - }
|
| - } else {
|
| - if (llvm::isa<OperandARM32Mem>(Src0))
|
| - ActualOpcode = IceString("ldr") + getWidthString(Dest->getType());
|
| - }
|
| - Str << "\t" << ActualOpcode << getPredicate() << "\t";
|
| - getDest()->emit(Func);
|
| - Str << ", ";
|
| - getSrc(0)->emit(Func);
|
| - } else {
|
| - Variable *Src0 = llvm::cast<Variable>(getSrc(0));
|
| - assert(Src0->hasReg());
|
| - Str << "\t"
|
| - << "str" << getPredicate() << "\t";
|
| - Src0->emit(Func);
|
| - Str << ", ";
|
| - Dest->emit(Func);
|
| - }
|
| -}
|
| -
|
| -template <> void InstARM32Mov::emitIAS(const Cfg *Func) const {
|
| - assert(getSrcSize() == 1);
|
| - (void)Func;
|
| - llvm_unreachable("Not yet implemented");
|
| -}
|
| -
|
| -template <> void InstARM32Vldr::emit(const Cfg *Func) const {
|
| +void InstARM32Mov::emitMultiDestSingleSource(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| Ostream &Str = Func->getContext()->getStrEmit();
|
| - assert(getSrcSize() == 1);
|
| - assert(getDest()->hasReg());
|
| - Str << "\t" << Opcode << getPredicate() << "\t";
|
| - getDest()->emit(Func);
|
| - Str << ", ";
|
| - getSrc(0)->emit(Func);
|
| -}
|
| + auto *Dest = llvm::cast<Variable64On32>(getDest());
|
| + Operand *Src = getSrc(0);
|
|
|
| -template <> void InstARM32Vldr::emitIAS(const Cfg *Func) const {
|
| - assert(getSrcSize() == 1);
|
| - (void)Func;
|
| - llvm_unreachable("Not yet implemented");
|
| -}
|
| -
|
| -void InstARM32Vmov::emitMultiDestSingleSource(const Cfg *Func) const {
|
| - if (!BuildDefs::dump())
|
| - return;
|
| - Ostream &Str = Func->getContext()->getStrEmit();
|
| - Variable *Dest0 = getDest();
|
| - Operand *Src0 = getSrc(0);
|
| -
|
| - assert(Dest0->hasReg());
|
| - assert(Dest1->hasReg());
|
| - assert(!llvm::isa<OperandARM32Mem>(Src0));
|
| + assert(Dest->getType() == IceType_i64);
|
| + assert(Dest->getHi()->hasReg());
|
| + assert(Dest->getLo()->hasReg());
|
| + assert(!llvm::isa<OperandARM32Mem>(Src));
|
|
|
| Str << "\t"
|
| << "vmov" << getPredicate() << "\t";
|
| - Dest0->emit(Func);
|
| + Dest->getLo()->emit(Func);
|
| Str << ", ";
|
| - Dest1->emit(Func);
|
| + Dest->getHi()->emit(Func);
|
| Str << ", ";
|
| - Src0->emit(Func);
|
| + Src->emit(Func);
|
| }
|
|
|
| -void InstARM32Vmov::emitSingleDestMultiSource(const Cfg *Func) const {
|
| +void InstARM32Mov::emitSingleDestMultiSource(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| Ostream &Str = Func->getContext()->getStrEmit();
|
| - Variable *Dest0 = getDest();
|
| - Operand *Src0 = getSrc(0);
|
| - Operand *Src1 = getSrc(1);
|
| + Variable *Dest = getDest();
|
| + auto *Src = llvm::cast<Variable64On32>(getSrc(0));
|
|
|
| - assert(Dest0->hasReg());
|
| - assert(!llvm::isa<OperandARM32Mem>(Src0));
|
| - assert(!llvm::isa<OperandARM32Mem>(Src1));
|
| + assert(Src->getType() == IceType_i64);
|
| + assert(Src->getHi()->hasReg());
|
| + assert(Src->getLo()->hasReg());
|
| + assert(Dest->hasReg());
|
|
|
| Str << "\t"
|
| << "vmov" << getPredicate() << "\t";
|
| - Dest0->emit(Func);
|
| + Dest->emit(Func);
|
| Str << ", ";
|
| - Src0->emit(Func);
|
| + Src->getLo()->emit(Func);
|
| Str << ", ";
|
| - Src1->emit(Func);
|
| + Src->getHi()->emit(Func);
|
| }
|
|
|
| namespace {
|
| +
|
| bool isVariableWithoutRegister(const Operand *Op) {
|
| if (const auto *OpV = llvm::dyn_cast<const Variable>(Op)) {
|
| return !OpV->hasReg();
|
| }
|
| return false;
|
| }
|
| -
|
| bool isMemoryAccess(Operand *Op) {
|
| return isVariableWithoutRegister(Op) || llvm::isa<OperandARM32Mem>(Op);
|
| }
|
| @@ -561,27 +504,38 @@ bool isMemoryAccess(Operand *Op) {
|
| bool isMoveBetweenCoreAndVFPRegisters(Variable *Dest, Operand *Src) {
|
| const Type DestTy = Dest->getType();
|
| const Type SrcTy = Src->getType();
|
| - assert(!(isScalarIntegerType(DestTy) && isScalarIntegerType(SrcTy)) &&
|
| - "At most one of vmov's operands can be a core register.");
|
| - return isScalarIntegerType(DestTy) || isScalarIntegerType(SrcTy);
|
| + return !isVectorType(DestTy) && !isVectorType(SrcTy) &&
|
| + (isScalarIntegerType(DestTy) == isScalarFloatingType(SrcTy));
|
| }
|
| +
|
| } // end of anonymous namespace
|
|
|
| -void InstARM32Vmov::emitSingleDestSingleSource(const Cfg *Func) const {
|
| +void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| Ostream &Str = Func->getContext()->getStrEmit();
|
| Variable *Dest = getDest();
|
| +
|
| if (Dest->hasReg()) {
|
| + Type DestTy = Dest->getType();
|
| Operand *Src0 = getSrc(0);
|
| - const char *ActualOpcode = isMemoryAccess(Src0) ? "vldr" : "vmov";
|
| + const bool DestIsVector = isVectorType(DestTy);
|
| + const bool DestIsScalarFP = isScalarFloatingType(Dest->getType());
|
| + const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
|
| + const char *LoadOpcode =
|
| + DestIsVector ? "vld1" : (DestIsScalarFP ? "vldr" : "ldr");
|
| + const char *RegMovOpcode =
|
| + (DestIsVector || DestIsScalarFP || CoreVFPMove) ? "vmov" : "mov";
|
| + const char *ActualOpcode = isMemoryAccess(Src0) ? LoadOpcode : RegMovOpcode;
|
| // when vmov{c}'ing, we need to emit a width string. Otherwise, the
|
| // assembler might be tempted to assume we want a vector vmov{c}, and that
|
| // is disallowed because ARM.
|
| + const char *NoWidthString = "";
|
| const char *WidthString =
|
| - (isMemoryAccess(Src0) || isMoveBetweenCoreAndVFPRegisters(Dest, Src0))
|
| - ? ""
|
| - : getVecWidthString(Src0->getType());
|
| + isMemoryAccess(Src0)
|
| + ? (DestIsVector ? ".64" : NoWidthString)
|
| + : (!CoreVFPMove ? getVecWidthString(DestTy) : NoWidthString);
|
| +
|
| Str << "\t" << ActualOpcode << getPredicate() << WidthString << "\t";
|
| Dest->emit(Func);
|
| Str << ", ";
|
| @@ -589,18 +543,24 @@ void InstARM32Vmov::emitSingleDestSingleSource(const Cfg *Func) const {
|
| } else {
|
| Variable *Src0 = llvm::cast<Variable>(getSrc(0));
|
| assert(Src0->hasReg());
|
| - Str << "\t"
|
| - "vstr" << getPredicate() << "\t";
|
| + const char *ActualOpcode =
|
| + isVectorType(Src0->getType())
|
| + ? "vst1"
|
| + : (isScalarFloatingType(Src0->getType()) ? "vstr" : "str");
|
| + const char *NoWidthString = "";
|
| + const char *WidthString =
|
| + isVectorType(Src0->getType()) ? ".64" : NoWidthString;
|
| + Str << "\t" << ActualOpcode << getPredicate() << WidthString << "\t";
|
| Src0->emit(Func);
|
| Str << ", ";
|
| Dest->emit(Func);
|
| }
|
| }
|
|
|
| -void InstARM32Vmov::emit(const Cfg *Func) const {
|
| +void InstARM32Mov::emit(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| - assert(isMultiDest() + isMultiSource() <= 1 && "Invalid vmov type.");
|
| + assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
|
| if (isMultiDest()) {
|
| emitMultiDestSingleSource(Func);
|
| return;
|
| @@ -614,21 +574,37 @@ void InstARM32Vmov::emit(const Cfg *Func) const {
|
| emitSingleDestSingleSource(Func);
|
| }
|
|
|
| -void InstARM32Vmov::emitIAS(const Cfg *Func) const {
|
| +void InstARM32Mov::emitIAS(const Cfg *Func) const {
|
| assert(getSrcSize() == 1);
|
| (void)Func;
|
| llvm_unreachable("Not yet implemented");
|
| }
|
|
|
| -void InstARM32Vmov::dump(const Cfg *Func) const {
|
| +void InstARM32Mov::dump(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| + assert(getSrcSize() == 1);
|
| Ostream &Str = Func->getContext()->getStrDump();
|
| - dumpOpcodePred(Str, "vmov", getDest()->getType());
|
| + Variable *Dest = getDest();
|
| + if (auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest)) {
|
| + Dest64->getLo()->dump(Func);
|
| + Str << ", ";
|
| + Dest64->getHi()->dump(Func);
|
| + } else {
|
| + Dest->dump(Func);
|
| + }
|
| +
|
| + dumpOpcodePred(Str, " = mov", getDest()->getType());
|
| Str << " ";
|
| - dumpDest(Func);
|
| - Str << ", ";
|
| - dumpSources(Func);
|
| +
|
| + Operand *Src = getSrc(0);
|
| + if (auto *Src64 = llvm::dyn_cast<Variable64On32>(Src)) {
|
| + Src64->getLo()->dump(Func);
|
| + Str << ", ";
|
| + Src64->getHi()->dump(Func);
|
| + } else {
|
| + Src->dump(Func);
|
| + }
|
| }
|
|
|
| void InstARM32Br::emit(const Cfg *Func) const {
|
| @@ -748,8 +724,16 @@ template <> void InstARM32Ldr::emit(const Cfg *Func) const {
|
| Ostream &Str = Func->getContext()->getStrEmit();
|
| assert(getSrcSize() == 1);
|
| assert(getDest()->hasReg());
|
| - Type Ty = getSrc(0)->getType();
|
| - Str << "\t" << Opcode << getWidthString(Ty) << getPredicate() << "\t";
|
| + Variable *Dest = getDest();
|
| + Type DestTy = Dest->getType();
|
| + const bool DestIsVector = isVectorType(DestTy);
|
| + const bool DestIsScalarFloat = isScalarFloatingType(DestTy);
|
| + const char *ActualOpcode =
|
| + DestIsVector ? "vld1" : (DestIsScalarFloat ? "vldr" : "ldr");
|
| + const char *VectorMarker = DestIsVector ? ".64" : "";
|
| + const char *WidthString = DestIsVector ? "" : getWidthString(DestTy);
|
| + Str << "\t" << ActualOpcode << WidthString << getPredicate() << VectorMarker
|
| + << "\t";
|
| getDest()->emit(Func);
|
| Str << ", ";
|
| getSrc(0)->emit(Func);
|
| @@ -799,15 +783,28 @@ template <> void InstARM32Movt::emit(const Cfg *Func) const {
|
| void InstARM32Pop::emit(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| - assert(Dests.size() > 0);
|
| + SizeT IntegerCount = 0;
|
| + for (const Operand *Op : Dests) {
|
| + if (isScalarIntegerType(Op->getType())) {
|
| + ++IntegerCount;
|
| + }
|
| + }
|
| Ostream &Str = Func->getContext()->getStrEmit();
|
| + if (IntegerCount == 0) {
|
| + Str << "\t@ empty pop";
|
| + return;
|
| + }
|
| Str << "\t"
|
| << "pop"
|
| << "\t{";
|
| - for (SizeT I = 0; I < Dests.size(); ++I) {
|
| - if (I > 0)
|
| - Str << ", ";
|
| - Dests[I]->emit(Func);
|
| + bool PrintComma = false;
|
| + for (const Operand *Op : Dests) {
|
| + if (isScalarIntegerType(Op->getType())) {
|
| + if (PrintComma)
|
| + Str << ", ";
|
| + Op->emit(Func);
|
| + PrintComma = true;
|
| + }
|
| }
|
| Str << "}";
|
| }
|
| @@ -866,12 +863,31 @@ void InstARM32AdjustStack::dump(const Cfg *Func) const {
|
| void InstARM32Push::emit(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| - assert(getSrcSize() > 0);
|
| + SizeT IntegerCount = 0;
|
| + for (SizeT i = 0; i < getSrcSize(); ++i) {
|
| + if (isScalarIntegerType(getSrc(i)->getType())) {
|
| + ++IntegerCount;
|
| + }
|
| + }
|
| Ostream &Str = Func->getContext()->getStrEmit();
|
| + if (IntegerCount == 0) {
|
| + Str << "\t"
|
| + << "@empty push";
|
| + return;
|
| + }
|
| Str << "\t"
|
| << "push"
|
| << "\t{";
|
| - emitSources(Func);
|
| + bool PrintComma = false;
|
| + for (SizeT i = 0; i < getSrcSize(); ++i) {
|
| + Operand *Op = getSrc(i);
|
| + if (isScalarIntegerType(Op->getType())) {
|
| + if (PrintComma)
|
| + Str << ", ";
|
| + Op->emit(Func);
|
| + PrintComma = true;
|
| + }
|
| + }
|
| Str << "}";
|
| }
|
|
|
| @@ -923,8 +939,12 @@ void InstARM32Str::emit(const Cfg *Func) const {
|
| Ostream &Str = Func->getContext()->getStrEmit();
|
| assert(getSrcSize() == 2);
|
| Type Ty = getSrc(0)->getType();
|
| - const char *Opcode = isScalarFloatingType(Ty) ? "vstr" : "str";
|
| - Str << "\t" << Opcode << getWidthString(Ty) << getPredicate() << "\t";
|
| + const bool IsVectorStore = isVectorType(Ty);
|
| + const char *Opcode =
|
| + IsVectorStore ? "vst1" : (isScalarFloatingType(Ty) ? "vstr" : "str");
|
| + const char *VecEltWidthString = IsVectorStore ? ".64" : "";
|
| + Str << "\t" << Opcode << getWidthString(Ty) << getPredicate()
|
| + << VecEltWidthString << "\t";
|
| getSrc(0)->emit(Func);
|
| Str << ", ";
|
| getSrc(1)->emit(Func);
|
| @@ -1119,6 +1139,33 @@ void InstARM32Vmrs::dump(const Cfg *Func) const {
|
| "FPSCR{n,z,c,v}";
|
| }
|
|
|
| +void InstARM32Vabs::emit(const Cfg *Func) const {
|
| + if (!BuildDefs::dump())
|
| + return;
|
| + Ostream &Str = Func->getContext()->getStrEmit();
|
| + assert(getSrcSize() == 1);
|
| + Str << "\t"
|
| + "vabs" << getPredicate() << getVecWidthString(getSrc(0)->getType())
|
| + << "\t";
|
| + getDest()->emit(Func);
|
| + Str << ", ";
|
| + getSrc(0)->emit(Func);
|
| +}
|
| +
|
| +void InstARM32Vabs::emitIAS(const Cfg *Func) const {
|
| + assert(getSrcSize() == 1);
|
| + (void)Func;
|
| + llvm_unreachable("Not yet implemented");
|
| +}
|
| +
|
| +void InstARM32Vabs::dump(const Cfg *Func) const {
|
| + if (!BuildDefs::dump())
|
| + return;
|
| + Ostream &Str = Func->getContext()->getStrDump();
|
| + dumpDest(Func);
|
| + Str << " = vabs" << getPredicate() << getVecWidthString(getSrc(0)->getType());
|
| +}
|
| +
|
| void OperandARM32Mem::emit(const Cfg *Func) const {
|
| if (!BuildDefs::dump())
|
| return;
|
| @@ -1128,13 +1175,13 @@ void OperandARM32Mem::emit(const Cfg *Func) const {
|
| switch (getAddrMode()) {
|
| case PostIndex:
|
| case NegPostIndex:
|
| - Str << "], ";
|
| + Str << "]";
|
| break;
|
| default:
|
| - Str << ", ";
|
| break;
|
| }
|
| if (isRegReg()) {
|
| + Str << ", ";
|
| if (isNegAddrMode()) {
|
| Str << "-";
|
| }
|
| @@ -1144,7 +1191,11 @@ void OperandARM32Mem::emit(const Cfg *Func) const {
|
| << getShiftAmt();
|
| }
|
| } else {
|
| - getOffset()->emit(Func);
|
| + ConstantInteger32 *Offset = getOffset();
|
| + if (Offset && Offset->getValue() != 0) {
|
| + Str << ", ";
|
| + Offset->emit(Func);
|
| + }
|
| }
|
| switch (getAddrMode()) {
|
| case Offset:
|
|
|