Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Unified Diff: src/IceInstARM32.h

Issue 1151663004: Subzero ARM: do lowerIcmp, lowerBr, and a bit of lowerCall. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: fix Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/IceConditionCodesARM32.h ('k') | src/IceInstARM32.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/IceInstARM32.h
diff --git a/src/IceInstARM32.h b/src/IceInstARM32.h
index c8d01e64391a187b991822c73cb1e31cfeae38ce..1ee183106c325c8ba182dba9efbaa5a536c6a20c 100644
--- a/src/IceInstARM32.h
+++ b/src/IceInstARM32.h
@@ -16,6 +16,7 @@
#ifndef SUBZERO_SRC_ICEINSTARM32_H
#define SUBZERO_SRC_ICEINSTARM32_H
+#include "IceConditionCodesARM32.h"
#include "IceDefs.h"
#include "IceInst.h"
#include "IceInstARM32.def"
@@ -237,6 +238,9 @@ private:
Operand *ShiftAmt;
};
+// Base class for ARM instructions. While most ARM instructions can be
+// conditionally executed, a few of them are not predicable (halt,
+// memory barriers, etc.).
class InstARM32 : public InstTarget {
InstARM32() = delete;
InstARM32(const InstARM32 &) = delete;
@@ -248,8 +252,12 @@ public:
Adc,
Add,
And,
+ Br,
+ Call,
+ Cmp,
Eor,
Ldr,
+ Lsl,
Mla,
Mov,
Movt,
@@ -264,6 +272,7 @@ public:
};
static const char *getWidthString(Type Ty);
+ static CondARM32::Cond getOppositeCondition(CondARM32::Cond Cond);
void dump(const Cfg *Func) const override;
@@ -276,23 +285,51 @@ 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);
+// A predicable ARM instruction.
+class InstARM32Pred : public InstARM32 {
+ InstARM32Pred() = delete;
+ InstARM32Pred(const InstARM32Pred &) = delete;
+ InstARM32Pred &operator=(const InstARM32Pred &) = delete;
-// TODO(jvoung): add condition codes if instruction can be predicated.
+public:
+ InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest,
+ CondARM32::Cond Predicate)
+ : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {}
+
+ CondARM32::Cond getPredicate() const { return Predicate; }
+ void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; }
+
+ static const char *predString(CondARM32::Cond Predicate);
+ void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const;
+
+ // Shared emit routines for common forms of instructions.
+ static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst,
+ const Cfg *Func);
+ static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst,
+ const Cfg *Func, bool SetFlags);
+
+protected:
+ CondARM32::Cond Predicate;
+};
+
+template <typename StreamType>
+inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) {
+ Stream << InstARM32Pred::predString(Predicate);
+ return Stream;
+}
// Instructions of the form x := op(y).
template <InstARM32::InstKindARM32 K>
-class InstARM32UnaryopGPR : public InstARM32 {
+class InstARM32UnaryopGPR : public InstARM32Pred {
InstARM32UnaryopGPR() = delete;
InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete;
InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete;
public:
- static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) {
+ static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src,
+ CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32UnaryopGPR>())
- InstARM32UnaryopGPR(Func, Dest, Src);
+ InstARM32UnaryopGPR(Func, Dest, Src, Predicate);
}
void emit(const Cfg *Func) const override {
if (!ALLOW_DUMP)
@@ -313,14 +350,17 @@ public:
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
- Str << " = " << Opcode << "." << getDest()->getType() << " ";
+ Str << " = ";
+ dumpOpcodePred(Str, Opcode, getDest()->getType());
+ Str << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
- InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src)
- : InstARM32(Func, K, 1, Dest) {
+ InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src,
+ CondARM32::Cond Predicate)
+ : InstARM32Pred(Func, K, 1, Dest, Predicate) {
addSource(Src);
}
~InstARM32UnaryopGPR() override {}
@@ -329,16 +369,17 @@ private:
// Instructions of the form x := x op y.
template <InstARM32::InstKindARM32 K>
-class InstARM32TwoAddrGPR : public InstARM32 {
+class InstARM32TwoAddrGPR : public InstARM32Pred {
InstARM32TwoAddrGPR() = delete;
InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete;
InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete;
public:
// Dest must be a register.
- static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src) {
+ static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src,
+ CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32TwoAddrGPR>())
- InstARM32TwoAddrGPR(Func, Dest, Src);
+ InstARM32TwoAddrGPR(Func, Dest, Src, Predicate);
}
void emit(const Cfg *Func) const override {
if (!ALLOW_DUMP)
@@ -354,14 +395,17 @@ public:
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
- Str << " = " << Opcode << "." << getDest()->getType() << " ";
+ Str << " = ";
+ dumpOpcodePred(Str, Opcode, getDest()->getType());
+ Str << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
- InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src)
- : InstARM32(Func, K, 2, Dest) {
+ InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src,
+ CondARM32::Cond Predicate)
+ : InstARM32Pred(Func, K, 2, Dest, Predicate) {
addSource(Dest);
addSource(Src);
}
@@ -372,15 +416,16 @@ private:
// Base class for assignment instructions.
// These can be tested for redundancy (and elided if redundant).
template <InstARM32::InstKindARM32 K>
-class InstARM32Movlike : public InstARM32 {
+class InstARM32Movlike : public InstARM32Pred {
InstARM32Movlike() = delete;
InstARM32Movlike(const InstARM32Movlike &) = delete;
InstARM32Movlike &operator=(const InstARM32Movlike &) = delete;
public:
- static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source) {
+ static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source,
+ CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32Movlike>())
- InstARM32Movlike(Func, Dest, Source);
+ InstARM32Movlike(Func, Dest, Source, Predicate);
}
bool isRedundantAssign() const override {
return checkForRedundantAssign(getDest(), getSrc(0));
@@ -392,7 +437,8 @@ public:
if (!ALLOW_DUMP)
return;
Ostream &Str = Func->getContext()->getStrDump();
- Str << Opcode << "." << getDest()->getType() << " ";
+ dumpOpcodePred(Str, Opcode, getDest()->getType());
+ Str << " ";
dumpDest(Func);
Str << ", ";
dumpSources(Func);
@@ -400,8 +446,9 @@ public:
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
- InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source)
- : InstARM32(Func, K, 1, Dest) {
+ InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source,
+ CondARM32::Cond Predicate)
+ : InstARM32Pred(Func, K, 1, Dest, Predicate) {
addSource(Source);
}
~InstARM32Movlike() override {}
@@ -412,7 +459,7 @@ private:
// 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 {
+class InstARM32ThreeAddrGPR : public InstARM32Pred {
InstARM32ThreeAddrGPR() = delete;
InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete;
InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete;
@@ -422,9 +469,10 @@ public:
// Dest and Src1 must be registers.
static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest,
Variable *Src1, Operand *Src2,
+ CondARM32::Cond Predicate,
bool SetFlags = false) {
return new (Func->allocate<InstARM32ThreeAddrGPR>())
- InstARM32ThreeAddrGPR(Func, Dest, Src1, Src2, SetFlags);
+ InstARM32ThreeAddrGPR(Func, Dest, Src1, Src2, Predicate, SetFlags);
}
void emit(const Cfg *Func) const override {
if (!ALLOW_DUMP)
@@ -440,16 +488,17 @@ public:
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
- Str << " = " << Opcode << (SetFlags ? "s" : "") << "."
- << getDest()->getType() << " ";
+ Str << " = ";
+ dumpOpcodePred(Str, Opcode, getDest()->getType());
+ Str << (SetFlags ? ".s " : " ");
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) {
+ Operand *Src2, CondARM32::Cond Predicate, bool SetFlags)
+ : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) {
addSource(Src1);
addSource(Src2);
}
@@ -462,6 +511,7 @@ typedef InstARM32ThreeAddrGPR<InstARM32::Adc> InstARM32Adc;
typedef InstARM32ThreeAddrGPR<InstARM32::Add> InstARM32Add;
typedef InstARM32ThreeAddrGPR<InstARM32::And> InstARM32And;
typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor;
+typedef InstARM32ThreeAddrGPR<InstARM32::Lsl> InstARM32Lsl;
typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul;
typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr;
typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc;
@@ -476,16 +526,123 @@ typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt;
typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw;
typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn;
+// Direct branch instruction.
+class InstARM32Br : public InstARM32Pred {
+ InstARM32Br() = delete;
+ InstARM32Br(const InstARM32Br &) = delete;
+ InstARM32Br &operator=(const InstARM32Br &) = delete;
+
+public:
+ // Create a conditional branch to one of two nodes.
+ static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue,
+ CfgNode *TargetFalse, CondARM32::Cond Predicate) {
+ assert(Predicate != CondARM32::AL);
+ return new (Func->allocate<InstARM32Br>())
+ InstARM32Br(Func, TargetTrue, TargetFalse, Predicate);
+ }
+ // Create an unconditional branch to a node.
+ static InstARM32Br *create(Cfg *Func, CfgNode *Target) {
+ const CfgNode *NoCondTarget = nullptr;
+ return new (Func->allocate<InstARM32Br>())
+ InstARM32Br(Func, NoCondTarget, Target, CondARM32::AL);
+ }
+ // Create a non-terminator conditional branch to a node, with a
+ // fallthrough to the next instruction in the current node. This is
+ // used for switch lowering.
+ static InstARM32Br *create(Cfg *Func, CfgNode *Target,
+ CondARM32::Cond Predicate) {
+ assert(Predicate != CondARM32::AL);
+ const CfgNode *NoUncondTarget = nullptr;
+ return new (Func->allocate<InstARM32Br>())
+ InstARM32Br(Func, Target, NoUncondTarget, Predicate);
+ }
+ const CfgNode *getTargetTrue() const { return TargetTrue; }
+ const CfgNode *getTargetFalse() const { return TargetFalse; }
+ bool optimizeBranch(const CfgNode *NextNode);
+ uint32_t getEmitInstCount() const override {
+ uint32_t Sum = 0;
+ if (getTargetTrue())
+ ++Sum;
+ if (getTargetFalse())
+ ++Sum;
+ return Sum;
+ }
+ bool isUnconditionalBranch() const override {
+ return getPredicate() == CondARM32::AL;
+ }
+ bool repointEdge(CfgNode *OldNode, CfgNode *NewNode) override;
+ 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, Br); }
+
+private:
+ InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
+ CondARM32::Cond Predicate);
+ ~InstARM32Br() override {}
+ const CfgNode *TargetTrue;
+ const CfgNode *TargetFalse;
+};
+
+// Call instruction (bl/blx). Arguments should have already been pushed.
+// Technically bl and the register form of blx can be predicated, but we'll
+// leave that out until needed.
+class InstARM32Call : public InstARM32 {
+ InstARM32Call() = delete;
+ InstARM32Call(const InstARM32Call &) = delete;
+ InstARM32Call &operator=(const InstARM32Call &) = delete;
+
+public:
+ static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) {
+ return new (Func->allocate<InstARM32Call>())
+ InstARM32Call(Func, Dest, CallTarget);
+ }
+ Operand *getCallTarget() const { return getSrc(0); }
+ 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, Call); }
+
+private:
+ InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
+ ~InstARM32Call() override {}
+};
+
+// Integer compare instruction.
+class InstARM32Cmp : public InstARM32Pred {
+ InstARM32Cmp() = delete;
+ InstARM32Cmp(const InstARM32Cmp &) = delete;
+ InstARM32Cmp &operator=(const InstARM32Cmp &) = delete;
+
+public:
+ static InstARM32Cmp *create(Cfg *Func, Variable *Src1, Operand *Src2,
+ CondARM32::Cond Predicate) {
+ return new (Func->allocate<InstARM32Cmp>())
+ InstARM32Cmp(Func, Src1, Src2, Predicate);
+ }
+ 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, Cmp); }
+
+private:
+ InstARM32Cmp(Cfg *Func, Variable *Src1, Operand *Src2,
+ CondARM32::Cond Predicate);
+ ~InstARM32Cmp() override {}
+};
+
// Load instruction.
-class InstARM32Ldr : public InstARM32 {
+class InstARM32Ldr : public InstARM32Pred {
InstARM32Ldr() = delete;
InstARM32Ldr(const InstARM32Ldr &) = delete;
InstARM32Ldr &operator=(const InstARM32Ldr &) = delete;
public:
// Dest must be a register.
- static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem) {
- return new (Func->allocate<InstARM32Ldr>()) InstARM32Ldr(Func, Dest, Mem);
+ static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem,
+ CondARM32::Cond Predicate) {
+ return new (Func->allocate<InstARM32Ldr>())
+ InstARM32Ldr(Func, Dest, Mem, Predicate);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
@@ -493,12 +650,13 @@ public:
static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); }
private:
- InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem);
+ InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem,
+ CondARM32::Cond Predicate);
~InstARM32Ldr() override {}
};
// Multiply Accumulate: d := x * y + a
-class InstARM32Mla : public InstARM32 {
+class InstARM32Mla : public InstARM32Pred {
InstARM32Mla() = delete;
InstARM32Mla(const InstARM32Mla &) = delete;
InstARM32Mla &operator=(const InstARM32Mla &) = delete;
@@ -506,9 +664,10 @@ class InstARM32Mla : public InstARM32 {
public:
// Everything must be a register.
static InstARM32Mla *create(Cfg *Func, Variable *Dest, Variable *Src0,
- Variable *Src1, Variable *Acc) {
+ Variable *Src1, Variable *Acc,
+ CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32Mla>())
- InstARM32Mla(Func, Dest, Src0, Src1, Acc);
+ InstARM32Mla(Func, Dest, Src0, Src1, Acc, Predicate);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
@@ -517,7 +676,7 @@ public:
private:
InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1,
- Variable *Acc);
+ Variable *Acc, CondARM32::Cond Predicate);
~InstARM32Mla() override {}
};
@@ -526,6 +685,10 @@ private:
// instead of a generic "bx". This instruction also takes a Source
// operand (for non-void returning functions) for liveness analysis, though
// a FakeUse before the ret would do just as well.
+//
+// NOTE: Even though "bx" can be predicated, for now leave out the predication
+// since it's not yet known to be useful for Ret. That may complicate finding
+// the terminator instruction if it's not guaranteed to be executed.
class InstARM32Ret : public InstARM32 {
InstARM32Ret() = delete;
InstARM32Ret(const InstARM32Ret &) = delete;
@@ -547,7 +710,7 @@ private:
};
// Unsigned Multiply Long: d.lo, d.hi := x * y
-class InstARM32Umull : public InstARM32 {
+class InstARM32Umull : public InstARM32Pred {
InstARM32Umull() = delete;
InstARM32Umull(const InstARM32Umull &) = delete;
InstARM32Umull &operator=(const InstARM32Umull &) = delete;
@@ -555,9 +718,10 @@ class InstARM32Umull : public InstARM32 {
public:
// Everything must be a register.
static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi,
- Variable *Src0, Variable *Src1) {
+ Variable *Src0, Variable *Src1,
+ CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32Umull>())
- InstARM32Umull(Func, DestLo, DestHi, Src0, Src1);
+ InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
@@ -566,7 +730,7 @@ public:
private:
InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0,
- Variable *Src1);
+ Variable *Src1, CondARM32::Cond Predicate);
~InstARM32Umull() override {}
Variable *DestHi;
};
« no previous file with comments | « src/IceConditionCodesARM32.h ('k') | src/IceInstARM32.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698