Index: src/IceInst.cpp |
diff --git a/src/IceInst.cpp b/src/IceInst.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..743dcb6a2d4aad3b290f5c74d172031ab3853b41 |
--- /dev/null |
+++ b/src/IceInst.cpp |
@@ -0,0 +1,456 @@ |
+//===- subzero/src/IceInst.cpp - High-level instruction implementation ----===// |
+// |
+// The Subzero Code Generator |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// This file implements the Inst class, primarily the various |
+// subclass constructors and dump routines. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "IceCfg.h" |
+#include "IceCfgNode.h" |
+#include "IceInst.h" |
+#include "IceOperand.h" |
+ |
+namespace Ice { |
+ |
+namespace { |
+ |
+const struct { |
+ const char *DisplayString; |
+ bool IsCommutative; |
+} InstArithmeticAttributes[] = { |
+#define X(tag, str, commutative) \ |
+ { str, commutative } \ |
+ , |
+ ICEINSTARITHMETIC_TABLE |
+#undef X |
+ }; |
+const size_t InstArithmeticAttributesSize = |
+ sizeof(InstArithmeticAttributes) / sizeof(*InstArithmeticAttributes); |
JF
2014/04/26 20:20:56
array_lengthof
Jim Stichnoth
2014/04/27 15:04:57
Strangely, this doesn't work.
const size_t InstAr
Jim Stichnoth
2014/04/27 15:25:22
Done. Turns out you can't use array_lengthof for
|
+ |
+const struct { |
+ const char *DisplayString; |
+} InstCastAttributes[] = { |
+#define X(tag, str) \ |
+ { str } \ |
+ , |
+ ICEINSTCAST_TABLE |
+#undef X |
+ }; |
+const size_t InstCastAttributesSize = |
+ sizeof(InstCastAttributes) / sizeof(*InstCastAttributes); |
JF
2014/04/26 20:20:56
ditto
Jim Stichnoth
2014/04/27 15:25:22
Done.
|
+ |
+const struct { |
+ const char *DisplayString; |
+} InstFcmpAttributes[] = { |
+#define X(tag, str) \ |
+ { str } \ |
+ , |
+ ICEINSTFCMP_TABLE |
+#undef X |
+ }; |
+const size_t InstFcmpAttributesSize = |
+ sizeof(InstFcmpAttributes) / sizeof(*InstFcmpAttributes); |
JF
2014/04/26 20:20:56
ditto
Jim Stichnoth
2014/04/27 15:25:22
Done.
|
+ |
+const struct { |
+ const char *DisplayString; |
+} InstIcmpAttributes[] = { |
+#define X(tag, str) \ |
+ { str } \ |
+ , |
+ ICEINSTICMP_TABLE |
+#undef X |
+ }; |
+const size_t InstIcmpAttributesSize = |
+ sizeof(InstIcmpAttributes) / sizeof(*InstIcmpAttributes); |
JF
2014/04/26 20:20:56
ditto
Jim Stichnoth
2014/04/27 15:25:22
Done.
|
+ |
+} // end of anonymous namespace |
+ |
+Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
+ : Kind(Kind), Number(Func->newInstNumber()), Deleted(false), |
+ HasSideEffects(false), Dest(Dest), MaxSrcs(MaxSrcs), NumSrcs(0), |
+ Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)) {} |
+ |
+void Inst::updateVars(CfgNode *Node) { |
+ if (Dest) |
+ Dest->setDefinition(this, Node); |
+ |
+ SizeT VarIndex = 0; |
+ for (SizeT I = 0; I < getSrcSize(); ++I) { |
+ Operand *Src = getSrc(I); |
+ SizeT NumVars = Src->getNumVars(); |
+ for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
+ Variable *Var = Src->getVar(J); |
+ Var->setUse(this, Node); |
+ } |
+ } |
+} |
+ |
+InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t Align, |
+ Variable *Dest) |
+ : Inst(Func, Inst::Alloca, 1, Dest), Align(Align) { |
+ // Verify Align is 0 or a power of 2. |
+ assert(Align == 0 || !(Align & (Align - 1))); |
JF
2014/04/26 20:20:56
llvm::isPowerOf2_32
Jim Stichnoth
2014/04/27 15:04:57
Done.
|
+ addSource(ByteCount); |
+} |
+ |
+InstArithmetic::InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, |
+ Operand *Source1, Operand *Source2) |
+ : Inst(Func, Inst::Arithmetic, 2, Dest), Op(Op) { |
+ addSource(Source1); |
+ addSource(Source2); |
+} |
+ |
+bool InstArithmetic::isCommutative() const { |
+ return InstArithmeticAttributes[getOp()].IsCommutative; |
+} |
+ |
+InstAssign::InstAssign(Cfg *Func, Variable *Dest, Operand *Source) |
+ : Inst(Func, Inst::Assign, 1, Dest) { |
+ addSource(Source); |
+} |
+ |
+// If TargetTrue==TargetFalse, we turn it into an unconditional |
+// branch. This ensures that, along with the 'switch' instruction |
+// semantics, there is at most one edge from one node to another. |
+InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, |
+ CfgNode *TargetFalse) |
+ : Inst(Func, Inst::Br, 1, NULL), TargetFalse(TargetFalse), |
+ TargetTrue(TargetTrue) { |
+ if (TargetTrue == TargetFalse) { |
+ TargetTrue = NULL; // turn into unconditional version |
+ } else { |
+ addSource(Source); |
+ } |
+} |
+ |
+InstBr::InstBr(Cfg *Func, CfgNode *Target) |
+ : Inst(Func, Inst::Br, 0, NULL), TargetFalse(Target), TargetTrue(NULL) {} |
+ |
+NodeList InstBr::getTerminatorEdges() const { |
+ NodeList OutEdges; |
+ OutEdges.push_back(TargetFalse); |
+ if (TargetTrue) |
+ OutEdges.push_back(TargetTrue); |
+ return OutEdges; |
+} |
+ |
+InstCast::InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source) |
+ : Inst(Func, Inst::Cast, 1, Dest), CastKind(CastKind) { |
+ addSource(Source); |
+} |
+ |
+InstFcmp::InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, |
+ Operand *Source2) |
+ : Inst(Func, Inst::Fcmp, 2, Dest), Condition(Condition) { |
+ addSource(Source1); |
+ addSource(Source2); |
+} |
+ |
+InstIcmp::InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, |
+ Operand *Source2) |
+ : Inst(Func, Inst::Icmp, 2, Dest), Condition(Condition) { |
+ addSource(Source1); |
+ addSource(Source2); |
+} |
+ |
+InstLoad::InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr) |
+ : Inst(Func, Inst::Load, 1, Dest) { |
+ addSource(SourceAddr); |
+} |
+ |
+InstPhi::InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest) |
+ : Inst(Func, Phi, MaxSrcs, Dest) { |
+ Labels = Func->allocateArrayOf<CfgNode *>(MaxSrcs); |
+} |
+ |
+// TODO: A Switch instruction (and maybe others) can add duplicate |
+// edges. We may want to de-dup Phis and validate consistency (i.e., |
+// the source operands are the same for duplicate edges), though it |
+// seems the current lowering code is OK with this situation. |
+void InstPhi::addArgument(Operand *Source, CfgNode *Label) { |
+ Labels[getSrcSize()] = Label; |
+ addSource(Source); |
+} |
+ |
+InstRet::InstRet(Cfg *Func, Operand *RetValue) |
+ : Inst(Func, Ret, RetValue ? 1 : 0, NULL) { |
+ if (RetValue) |
+ addSource(RetValue); |
+} |
+ |
+InstSelect::InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, |
+ Operand *SourceTrue, Operand *SourceFalse) |
+ : Inst(Func, Inst::Select, 3, Dest) { |
+ assert(Condition->getType() == IceType_i1); |
+ addSource(Condition); |
+ addSource(SourceTrue); |
+ addSource(SourceFalse); |
+} |
+ |
+InstStore::InstStore(Cfg *Func, Operand *Data, Operand *Addr) |
+ : Inst(Func, Inst::Store, 2, NULL) { |
+ addSource(Data); |
+ addSource(Addr); |
+} |
+ |
+InstSwitch::InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, |
+ CfgNode *LabelDefault) |
+ : Inst(Func, Inst::Switch, 1, NULL), LabelDefault(LabelDefault), |
+ NumCases(NumCases) { |
+ addSource(Source); |
+ Values = Func->allocateArrayOf<uint64_t>(NumCases); |
+ Labels = Func->allocateArrayOf<CfgNode *>(NumCases); |
+ // Initialize in case buggy code doesn't set all entries |
+ for (SizeT I = 0; I < NumCases; ++I) { |
+ Values[I] = 0; |
+ Labels[I] = NULL; |
+ } |
+} |
+ |
+void InstSwitch::addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label) { |
+ assert(CaseIndex < NumCases); |
+ Values[CaseIndex] = Value; |
+ Labels[CaseIndex] = Label; |
+} |
+ |
+NodeList InstSwitch::getTerminatorEdges() const { |
+ NodeList OutEdges; |
+ OutEdges.push_back(LabelDefault); |
+ for (SizeT I = 0; I < NumCases; ++I) { |
+ OutEdges.push_back(Labels[I]); |
+ } |
+ return OutEdges; |
+} |
+ |
+InstUnreachable::InstUnreachable(Cfg *Func) |
+ : Inst(Func, Inst::Unreachable, 0, NULL) {} |
+ |
+// ======================== Dump routines ======================== // |
+ |
+void Inst::dumpDecorated(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ if (!Func->getContext()->isVerbose(IceV_Deleted) && isDeleted()) |
+ return; |
+ if (Func->getContext()->isVerbose(IceV_InstNumbers)) { |
+ char buf[30]; |
+ int32_t Number = getNumber(); |
+ if (Number < 0) |
+ snprintf(buf, llvm::array_lengthof(buf), "[XXX]"); |
+ else |
+ snprintf(buf, llvm::array_lengthof(buf), "[%3d]", Number); |
+ Str << buf; |
+ } |
+ Str << " "; |
+ if (isDeleted()) |
+ Str << " //"; |
+ dump(Func); |
+ Str << "\n"; |
+} |
+ |
+void Inst::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " =~ "; |
+ dumpSources(Func); |
+} |
+ |
+void Inst::dumpSources(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ for (SizeT I = 0; I < getSrcSize(); ++I) { |
+ if (I > 0) |
+ Str << ", "; |
+ getSrc(I)->dump(Func); |
+ } |
+} |
+ |
+void Inst::dumpDest(const Cfg *Func) const { |
+ if (getDest()) |
+ getDest()->dump(Func); |
+} |
+ |
+void InstAlloca::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = alloca i8, i32 "; |
+ getSizeInBytes()->dump(Func); |
+ Str << ", align " << Align; |
+} |
+ |
+void InstArithmetic::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = " << InstArithmeticAttributes[getOp()].DisplayString << " " |
+ << getDest()->getType() << " "; |
+ dumpSources(Func); |
+} |
+ |
+void InstAssign::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = " << getDest()->getType() << " "; |
+ dumpSources(Func); |
+} |
+ |
+void InstBr::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << "br "; |
+ if (!isUnconditional()) { |
+ Str << "i1 "; |
+ getCondition()->dump(Func); |
+ Str << ", label %" << getTargetTrue()->getName() << ", "; |
+ } |
+ Str << "label %" << getTargetFalse()->getName(); |
+} |
+ |
+void InstCall::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ if (getDest()) { |
+ dumpDest(Func); |
+ Str << " = "; |
+ } |
+ Str << "call "; |
+ if (getDest()) |
+ Str << getDest()->getType(); |
+ else |
+ Str << "void"; |
+ Str << " "; |
+ getCallTarget()->dump(Func); |
+ Str << "("; |
+ for (SizeT I = 0; I < getNumArgs(); ++I) { |
+ if (I > 0) |
+ Str << ", "; |
+ Str << getArg(I)->getType() << " "; |
+ getArg(I)->dump(Func); |
+ } |
+ Str << ")"; |
+} |
+ |
+void InstCast::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = " << InstCastAttributes[getCastKind()].DisplayString << " " |
+ << getSrc(0)->getType() << " "; |
+ dumpSources(Func); |
+ Str << " to " << getDest()->getType(); |
+} |
+ |
+void InstIcmp::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = icmp " << InstIcmpAttributes[getCondition()].DisplayString << " " |
+ << getSrc(0)->getType() << " "; |
+ dumpSources(Func); |
+} |
+ |
+void InstFcmp::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = fcmp " << InstFcmpAttributes[getCondition()].DisplayString << " " |
+ << getSrc(0)->getType() << " "; |
+ dumpSources(Func); |
+} |
+ |
+void InstLoad::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Type Ty = getDest()->getType(); |
+ Str << " = load " << Ty << "* "; |
+ dumpSources(Func); |
+ switch (Ty) { |
+ case IceType_f32: |
+ Str << ", align 4"; |
+ break; |
+ case IceType_f64: |
+ Str << ", align 8"; |
+ break; |
+ default: |
+ Str << ", align 1"; |
+ break; |
JF
2014/04/26 20:20:56
Won't you need to factor alignment out at some poi
Jim Stichnoth
2014/04/27 15:04:57
Good point. I added alignment to the IceTypes.def
|
+ } |
+} |
+ |
+void InstStore::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ Type Ty = getData()->getType(); |
+ Str << "store " << Ty << " "; |
+ getData()->dump(Func); |
+ Str << ", " << Ty << "* "; |
+ getAddr()->dump(Func); |
+ Str << ", align "; |
+ switch (Ty) { |
+ case IceType_f32: |
+ Str << "4"; |
+ break; |
+ case IceType_f64: |
+ Str << "8"; |
+ break; |
+ default: |
+ Str << "1"; |
+ break; |
+ } |
+} |
+ |
+void InstSwitch::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ Type Ty = getComparison()->getType(); |
+ Str << "switch " << Ty << " "; |
+ getSrc(0)->dump(Func); |
+ Str << ", label %" << getLabelDefault()->getName() << " [\n"; |
+ for (SizeT I = 0; I < getNumCases(); ++I) { |
+ Str << " " << Ty << " " << getValue(I) << ", label %" |
+ << getLabel(I)->getName() << "\n"; |
+ } |
+ Str << " ]"; |
+} |
+ |
+void InstPhi::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Str << " = phi " << getDest()->getType() << " "; |
+ for (SizeT I = 0; I < getSrcSize(); ++I) { |
+ if (I > 0) |
+ Str << ", "; |
+ Str << "[ "; |
+ getSrc(I)->dump(Func); |
+ Str << ", %" << Labels[I]->getName() << " ]"; |
+ } |
+} |
+ |
+void InstRet::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ Type Ty = hasRetValue() ? getSrc(0)->getType() : IceType_void; |
+ Str << "ret " << Ty; |
+ if (hasRetValue()) { |
+ Str << " "; |
+ dumpSources(Func); |
+ } |
+} |
+ |
+void InstSelect::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ dumpDest(Func); |
+ Operand *Condition = getCondition(); |
+ Operand *TrueOp = getTrueOperand(); |
+ Operand *FalseOp = getFalseOperand(); |
+ Str << " = select " << Condition->getType() << " "; |
+ Condition->dump(Func); |
+ Str << ", " << TrueOp->getType() << " "; |
+ TrueOp->dump(Func); |
+ Str << ", " << FalseOp->getType() << " "; |
+ FalseOp->dump(Func); |
+} |
+ |
+void InstUnreachable::dump(const Cfg *Func) const { |
+ Ostream &Str = Func->getContext()->getStrDump(); |
+ Str << "unreachable"; |
+} |
+ |
+} // end of namespace Ice |