Index: src/IceInstARM32.h |
diff --git a/src/IceInstARM32.h b/src/IceInstARM32.h |
index 2e3f764d2953740ccfbbf3c4aa526af9c4c96e14..c8d01e64391a187b991822c73cb1e31cfeae38ce 100644 |
--- a/src/IceInstARM32.h |
+++ b/src/IceInstARM32.h |
@@ -245,12 +245,22 @@ class InstARM32 : public InstTarget { |
public: |
enum InstKindARM32 { |
k__Start = Inst::Target, |
+ Adc, |
+ Add, |
+ And, |
+ Eor, |
+ Ldr, |
+ Mla, |
Mov, |
Movt, |
Movw, |
+ Mul, |
Mvn, |
+ Orr, |
Ret, |
- Ldr |
+ Sbc, |
+ Sub, |
+ Umull |
}; |
static const char *getWidthString(Type Ty); |
@@ -267,6 +277,8 @@ protected: |
}; |
void emitTwoAddr(const char *Opcode, const Inst *Inst, const Cfg *Func); |
+void emitThreeAddr(const char *Opcode, const Inst *Inst, const Cfg *Func, |
+ bool SetFlags); |
// TODO(jvoung): add condition codes if instruction can be predicated. |
@@ -397,6 +409,63 @@ private: |
static const char *Opcode; |
}; |
+// Instructions of the form x := y op z. May have the side-effect of setting |
+// status flags. |
+template <InstARM32::InstKindARM32 K> |
+class InstARM32ThreeAddrGPR : public InstARM32 { |
+ InstARM32ThreeAddrGPR() = delete; |
+ InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; |
+ InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; |
+ |
+public: |
+ // Create an ordinary binary-op instruction like add, and sub. |
+ // Dest and Src1 must be registers. |
+ static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, |
+ Variable *Src1, Operand *Src2, |
+ bool SetFlags = false) { |
+ return new (Func->allocate<InstARM32ThreeAddrGPR>()) |
+ InstARM32ThreeAddrGPR(Func, Dest, Src1, Src2, SetFlags); |
+ } |
+ void emit(const Cfg *Func) const override { |
+ if (!ALLOW_DUMP) |
+ return; |
+ emitThreeAddr(Opcode, this, Func, SetFlags); |
+ } |
+ void emitIAS(const Cfg *Func) const override { |
+ (void)Func; |
+ llvm::report_fatal_error("Not yet implemented"); |
+ } |
+ void dump(const Cfg *Func) const override { |
+ if (!ALLOW_DUMP) |
+ return; |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = " << Opcode << (SetFlags ? "s" : "") << "." |
+ << getDest()->getType() << " "; |
+ dumpSources(Func); |
+ } |
+ static bool classof(const Inst *Inst) { return isClassof(Inst, K); } |
+ |
+private: |
+ InstARM32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src1, |
+ Operand *Src2, bool SetFlags) |
+ : InstARM32(Func, K, 2, Dest), SetFlags(SetFlags) { |
+ addSource(Src1); |
+ addSource(Src2); |
+ } |
+ ~InstARM32ThreeAddrGPR() override {} |
+ static const char *Opcode; |
+ bool SetFlags; |
+}; |
+ |
+typedef InstARM32ThreeAddrGPR<InstARM32::Adc> InstARM32Adc; |
+typedef InstARM32ThreeAddrGPR<InstARM32::Add> InstARM32Add; |
+typedef InstARM32ThreeAddrGPR<InstARM32::And> InstARM32And; |
+typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor; |
+typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul; |
+typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr; |
+typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc; |
+typedef InstARM32ThreeAddrGPR<InstARM32::Sub> InstARM32Sub; |
// Move instruction (variable <- flex). This is more of a pseudo-inst. |
// If var is a register, then we use "mov". If var is stack, then we use |
// "str" to store to the stack. |
@@ -428,6 +497,30 @@ private: |
~InstARM32Ldr() override {} |
}; |
+// Multiply Accumulate: d := x * y + a |
+class InstARM32Mla : public InstARM32 { |
+ InstARM32Mla() = delete; |
+ InstARM32Mla(const InstARM32Mla &) = delete; |
+ InstARM32Mla &operator=(const InstARM32Mla &) = delete; |
+ |
+public: |
+ // Everything must be a register. |
+ static InstARM32Mla *create(Cfg *Func, Variable *Dest, Variable *Src0, |
+ Variable *Src1, Variable *Acc) { |
+ return new (Func->allocate<InstARM32Mla>()) |
+ InstARM32Mla(Func, Dest, Src0, Src1, Acc); |
+ } |
+ void emit(const Cfg *Func) const override; |
+ void emitIAS(const Cfg *Func) const override; |
+ void dump(const Cfg *Func) const override; |
+ static bool classof(const Inst *Inst) { return isClassof(Inst, Mla); } |
+ |
+private: |
+ InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1, |
+ Variable *Acc); |
+ ~InstARM32Mla() override {} |
+}; |
+ |
// Ret pseudo-instruction. This is actually a "bx" instruction with |
// an "lr" register operand, but epilogue lowering will search for a Ret |
// instead of a generic "bx". This instruction also takes a Source |
@@ -453,6 +546,31 @@ private: |
~InstARM32Ret() override {} |
}; |
+// Unsigned Multiply Long: d.lo, d.hi := x * y |
+class InstARM32Umull : public InstARM32 { |
+ InstARM32Umull() = delete; |
+ InstARM32Umull(const InstARM32Umull &) = delete; |
+ InstARM32Umull &operator=(const InstARM32Umull &) = delete; |
+ |
+public: |
+ // Everything must be a register. |
+ static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi, |
+ Variable *Src0, Variable *Src1) { |
+ return new (Func->allocate<InstARM32Umull>()) |
+ InstARM32Umull(Func, DestLo, DestHi, Src0, Src1); |
+ } |
+ void emit(const Cfg *Func) const override; |
+ void emitIAS(const Cfg *Func) const override; |
+ void dump(const Cfg *Func) const override; |
+ static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); } |
+ |
+private: |
+ InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0, |
+ Variable *Src1); |
+ ~InstARM32Umull() override {} |
+ Variable *DestHi; |
+}; |
+ |
// Declare partial template specializations of emit() methods that |
// already have default implementations. Without this, there is the |
// possibility of ODR violations and link errors. |