Index: src/IceInstARM32.cpp |
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp |
index 9f54e85a99f203ce42ef9d34b7cb45f41a86ecae..6ac169862b063dcb3149c765a8ef9c0977d7f182 100644 |
--- a/src/IceInstARM32.cpp |
+++ b/src/IceInstARM32.cpp |
@@ -37,12 +37,57 @@ const struct TypeARM32Attributes_ { |
#undef X |
}; |
+const struct InstARM32ShiftAttributes_ { |
+ const char *EmitString; |
+} InstARM32ShiftAttributes[] = { |
+#define X(tag, emit) \ |
+ { emit } \ |
+ , |
+ ICEINSTARM32SHIFT_TABLE |
+#undef X |
+}; |
+ |
} // end of anonymous namespace |
const char *InstARM32::getWidthString(Type Ty) { |
return TypeARM32Attributes[Ty].WidthString; |
} |
+void emitTwoAddr(const char *Opcode, const Inst *Inst, const Cfg *Func) { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(Inst->getSrcSize() == 2); |
+ Variable *Dest = Inst->getDest(); |
+ assert(Dest == Inst->getSrc(0)); |
+ Operand *Src1 = Inst->getSrc(1); |
+ Str << "\t" << Opcode << "\t"; |
+ Dest->emit(Func); |
+ Str << ", "; |
+ Src1->emit(Func); |
+} |
+ |
+OperandARM32Mem::OperandARM32Mem(Cfg * /* Func */, Type Ty, Variable *Base, |
+ ConstantInteger32 *ImmOffset, AddrMode Mode) |
+ : OperandARM32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Index(nullptr), |
+ ShiftOp(kNoShift), ShiftAmt(0), Mode(Mode) { |
+ // The Neg modes are only needed for Reg +/- Reg. |
+ assert(!isNegAddrMode()); |
+ NumVars = 1; |
+ Vars = &this->Base; |
+} |
+ |
+OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, |
+ Variable *Index, ShiftKind ShiftOp, |
+ uint16_t ShiftAmt, AddrMode Mode) |
+ : OperandARM32(kMem, Ty), Base(Base), ImmOffset(0), Index(Index), |
+ ShiftOp(ShiftOp), ShiftAmt(ShiftAmt), Mode(Mode) { |
+ NumVars = 2; |
+ Vars = Func->allocateArrayOf<Variable *>(2); |
+ Vars[0] = Base; |
+ Vars[1] = Index; |
+} |
+ |
bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { |
int32_t Bits = SignExt ? TypeARM32Attributes[Ty].SExtAddrOffsetBits |
: TypeARM32Attributes[Ty].ZExtAddrOffsetBits; |
@@ -55,6 +100,52 @@ bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { |
return Utils::IsAbsoluteUint(Bits, Offset); |
} |
+OperandARM32FlexImm::OperandARM32FlexImm(Cfg * /* Func */, Type Ty, |
+ uint32_t Imm, uint32_t RotateAmt) |
+ : OperandARM32Flex(kFlexImm, Ty), Imm(Imm), RotateAmt(RotateAmt) { |
+ NumVars = 0; |
+ Vars = nullptr; |
+} |
+ |
+bool OperandARM32FlexImm::canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, |
+ uint32_t *Immed_8) { |
+ // Avoid the more expensive test for frequent small immediate values. |
+ if (Immediate <= 0xFF) { |
+ *RotateAmt = 0; |
+ *Immed_8 = Immediate; |
+ return true; |
+ } |
+ // Note that immediate must be unsigned for the test to work correctly. |
+ for (int Rot = 1; Rot < 16; Rot++) { |
+ uint32_t Imm8 = Utils::rotateLeft32(Immediate, 2 * Rot); |
+ if (Imm8 <= 0xFF) { |
+ *RotateAmt = Rot; |
+ *Immed_8 = Imm8; |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+OperandARM32FlexReg::OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, |
+ ShiftKind ShiftOp, Operand *ShiftAmt) |
+ : OperandARM32Flex(kFlexReg, Ty), Reg(Reg), ShiftOp(ShiftOp), |
+ ShiftAmt(ShiftAmt) { |
+ NumVars = 1; |
+ Variable *ShiftVar = llvm::dyn_cast_or_null<Variable>(ShiftAmt); |
+ if (ShiftVar) |
+ ++NumVars; |
+ Vars = Func->allocateArrayOf<Variable *>(NumVars); |
+ Vars[0] = Reg; |
+ if (ShiftVar) |
+ Vars[1] = ShiftVar; |
+} |
+ |
+InstARM32Ldr::InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem) |
+ : InstARM32(Func, InstARM32::Ldr, 1, Dest) { |
+ addSource(Mem); |
+} |
+ |
InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) |
: InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { |
addSource(LR); |
@@ -64,6 +155,14 @@ InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) |
// ======================== Dump routines ======================== // |
+// Two-addr ops |
+template <> const char *InstARM32Movt::Opcode = "movt"; |
+// Unary ops |
+template <> const char *InstARM32Movw::Opcode = "movw"; |
+template <> const char *InstARM32Mvn::Opcode = "mvn"; |
+// Mov-like ops |
+template <> const char *InstARM32Mov::Opcode = "mov"; |
+ |
void InstARM32::dump(const Cfg *Func) const { |
if (!ALLOW_DUMP) |
return; |
@@ -72,6 +171,101 @@ void InstARM32::dump(const Cfg *Func) const { |
Inst::dump(Func); |
} |
+template <> void InstARM32Mov::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(getSrcSize() == 1); |
+ Variable *Dest = getDest(); |
+ if (Dest->hasReg()) { |
+ Str << "\t" |
+ << "mov" |
+ << "\t"; |
+ getDest()->emit(Func); |
+ Str << ", "; |
+ getSrc(0)->emit(Func); |
+ } else { |
+ Variable *Src0 = llvm::cast<Variable>(getSrc(0)); |
+ assert(Src0->hasReg()); |
+ Str << "\t" |
+ << "str" |
+ << "\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"); |
+} |
+ |
+void InstARM32Ldr::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(getSrcSize() == 1); |
+ assert(getDest()->hasReg()); |
+ Type Ty = getSrc(0)->getType(); |
+ Str << "\t" |
+ << "ldr" << getWidthString(Ty) << "\t"; |
+ getDest()->emit(Func); |
+ Str << ", "; |
+ getSrc(0)->emit(Func); |
+} |
+ |
+void InstARM32Ldr::emitIAS(const Cfg *Func) const { |
+ assert(getSrcSize() == 2); |
+ (void)Func; |
+ llvm_unreachable("Not yet implemented"); |
+} |
+ |
+void InstARM32Ldr::dump(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << "ldr." << getSrc(0)->getType() << " "; |
+ dumpSources(Func); |
+} |
+ |
+template <> void InstARM32Movw::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(getSrcSize() == 1); |
+ Str << "\t" << Opcode << "\t"; |
+ getDest()->emit(Func); |
+ Str << ", "; |
+ Constant *Src0 = llvm::cast<Constant>(getSrc(0)); |
+ if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) { |
+ Str << "#:lower16:"; |
+ CR->emitWithoutPrefix(Func->getTarget()); |
+ } else { |
+ Src0->emit(Func); |
+ } |
+} |
+ |
+template <> void InstARM32Movt::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ assert(getSrcSize() == 2); |
+ Variable *Dest = getDest(); |
+ Constant *Src1 = llvm::cast<Constant>(getSrc(1)); |
+ Str << "\t" << Opcode << "\t"; |
+ Dest->emit(Func); |
+ Str << ", "; |
+ if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) { |
+ Str << "#:upper16:"; |
+ CR->emitWithoutPrefix(Func->getTarget()); |
+ } else { |
+ Src1->emit(Func); |
+ } |
+} |
+ |
void InstARM32Ret::emit(const Cfg *Func) const { |
if (!ALLOW_DUMP) |
return; |
@@ -98,4 +292,119 @@ void InstARM32Ret::dump(const Cfg *Func) const { |
dumpSources(Func); |
} |
+void OperandARM32Mem::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ Str << "["; |
+ getBase()->emit(Func); |
+ switch (getAddrMode()) { |
+ case PostIndex: |
+ case NegPostIndex: |
+ Str << "], "; |
+ break; |
+ default: |
+ Str << ", "; |
+ break; |
+ } |
+ if (isRegReg()) { |
+ if (isNegAddrMode()) { |
+ Str << "-"; |
+ } |
+ getIndex()->emit(Func); |
+ if (getShiftOp() != kNoShift) { |
+ Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" |
+ << getShiftAmt(); |
+ } |
+ } else { |
+ getOffset()->emit(Func); |
+ } |
+ switch (getAddrMode()) { |
+ case Offset: |
+ case NegOffset: |
+ Str << "]"; |
+ break; |
+ case PreIndex: |
+ case NegPreIndex: |
+ Str << "]!"; |
+ break; |
+ case PostIndex: |
+ case NegPostIndex: |
+ // Brace is already closed off. |
+ break; |
+ } |
+} |
+ |
+void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Str << "["; |
+ if (Func) |
+ getBase()->dump(Func); |
+ else |
+ getBase()->dump(Str); |
+ Str << ", "; |
+ if (isRegReg()) { |
+ if (isNegAddrMode()) { |
+ Str << "-"; |
+ } |
+ if (Func) |
+ getIndex()->dump(Func); |
+ else |
+ getIndex()->dump(Str); |
+ if (getShiftOp() != kNoShift) { |
+ Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" |
+ << getShiftAmt(); |
+ } |
+ } else { |
+ getOffset()->dump(Func, Str); |
+ } |
+ Str << "] AddrMode==" << getAddrMode() << "\n"; |
+} |
+ |
+void OperandARM32FlexImm::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ uint32_t Imm = getImm(); |
+ uint32_t RotateAmt = getRotateAmt(); |
+ Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt); |
+} |
+ |
+void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ uint32_t Imm = getImm(); |
+ uint32_t RotateAmt = getRotateAmt(); |
+ Str << "#(" << Imm << " ror 2*" << RotateAmt << ")"; |
+} |
+ |
+void OperandARM32FlexReg::emit(const Cfg *Func) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrEmit(); |
+ getReg()->emit(Func); |
+ if (getShiftOp() != kNoShift) { |
+ Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
+ getShiftAmt()->emit(Func); |
+ } |
+} |
+ |
+void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Variable *Reg = getReg(); |
+ if (Func) |
+ Reg->dump(Func); |
+ else |
+ Reg->dump(Str); |
+ if (getShiftOp() != kNoShift) { |
+ Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
+ if (Func) |
+ getShiftAmt()->dump(Func); |
+ else |
+ getShiftAmt()->dump(Str); |
+ } |
+} |
+ |
} // end of namespace Ice |