Chromium Code Reviews| Index: src/IceInstARM32.cpp |
| diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp |
| index aff4ef335ab2486335468c852a9a51eab7871c24..4ff7d89e07d0c05fbdd9db935764aef9d9fa841c 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,8 @@ 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); |
| + /*if (isScalarFloatingType(Ty)) |
|
Jim Stichnoth
2015/09/24 05:57:13
Explain or delete comment?
John
2015/09/24 21:28:39
Done.
|
| + return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset);*/ |
| return Utils::IsAbsoluteUint(Bits, Offset); |
| } |
| @@ -392,6 +392,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 +413,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 +449,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 +506,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 +545,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 +576,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 +726,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 +785,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 +865,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 +941,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 +1141,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 +1177,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 +1193,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: |