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

Unified Diff: src/IceInst.h

Issue 205613002: Initial skeleton of Subzero. (Closed) Base URL: https://gerrit.chromium.org/gerrit/p/native_client/pnacl-subzero.git@master
Patch Set: Use non-anonymous structs so that array_lengthof works Created 6 years, 8 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/IceGlobalContext.cpp ('k') | src/IceInst.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/IceInst.h
diff --git a/src/IceInst.h b/src/IceInst.h
new file mode 100644
index 0000000000000000000000000000000000000000..57f8b9e98d0f64fdcdcb1d311479002cf6b92f8f
--- /dev/null
+++ b/src/IceInst.h
@@ -0,0 +1,527 @@
+//===- subzero/src/IceInst.h - High-level instructions ----------*- C++ -*-===//
+//
+// The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the Inst class and its target-independent
+// subclasses, which represent the high-level Vanilla ICE instructions
+// and map roughly 1:1 to LLVM instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUBZERO_SRC_ICEINST_H
+#define SUBZERO_SRC_ICEINST_H
+
+#include "IceDefs.h"
+#include "IceInst.def"
+#include "IceTypes.h"
+
+// TODO: The Cfg structure, and instructions in particular, need to be
+// validated for things like valid operand types, valid branch
+// targets, proper ordering of Phi and non-Phi instructions, etc.
+// Most of the validity checking will be done in the bitcode reader.
+// We need a list of everything that should be validated, and tests
+// for each.
+
+namespace Ice {
+
+class Inst {
+public:
+ enum InstKind {
+ // Arbitrary (alphabetical) order, except put Unreachable first.
+ Unreachable,
+ Alloca,
+ Arithmetic,
+ Assign, // not part of LLVM/PNaCl bitcode
+ Br,
+ Call,
+ Cast,
+ Fcmp,
+ Icmp,
+ Load,
+ Phi,
+ Ret,
+ Select,
+ Store,
+ Switch
+ };
+ InstKind getKind() const { return Kind; }
+
+ int32_t getNumber() const { return Number; }
+
+ bool isDeleted() const { return Deleted; }
+ void setDeleted() { Deleted = true; }
+
+ bool hasSideEffects() const { return HasSideEffects; }
+
+ Variable *getDest() const { return Dest; }
+
+ SizeT getSrcSize() const { return NumSrcs; }
+ Operand *getSrc(SizeT I) const {
+ assert(I < getSrcSize());
+ return Srcs[I];
+ }
+
+ // Returns a list of out-edges corresponding to a terminator
+ // instruction, which is the last instruction of the block.
+ virtual NodeList getTerminatorEdges() const {
+ // All valid terminator instructions override this method. For
+ // the default implementation, we assert in case some CfgNode
+ // is constructed without a terminator instruction at the end.
+ llvm_unreachable(
+ "getTerminatorEdges() called on a non-terminator instruction");
+ return NodeList();
+ }
+
+ // Updates the status of the Variables contained within the
+ // instruction. In particular, it marks where the Dest variable is
+ // first assigned, and it tracks whether variables are live across
+ // basic blocks, i.e. used in a different block from their definition.
+ void updateVars(CfgNode *Node);
+
+ virtual void dump(const Cfg *Func) const;
+ void dumpDecorated(const Cfg *Func) const;
+ void dumpSources(const Cfg *Func) const;
+ void dumpDest(const Cfg *Func) const;
+
+ virtual ~Inst() {}
+
+protected:
+ Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest);
+ void addSource(Operand *Src) {
+ assert(Src);
+ assert(NumSrcs < MaxSrcs);
+ Srcs[NumSrcs++] = Src;
+ }
+ // The destroy() method lets the instruction cleanly release any
+ // memory that was allocated via the Cfg's allocator.
+ virtual void destroy(Cfg *Func) { Func->deallocateArrayOf<Operand *>(Srcs); }
+
+ const InstKind Kind;
+ // Number is the instruction number for describing live ranges.
+ int32_t Number;
+ // Deleted means irrevocably deleted.
+ bool Deleted;
+ // HasSideEffects means the instruction is something like a function
+ // call or a volatile load that can't be removed even if its Dest
+ // variable is not live.
+ bool HasSideEffects;
+
+ Variable *Dest;
+ const SizeT MaxSrcs; // only used for assert
+ SizeT NumSrcs;
+ Operand **Srcs;
+
+private:
+ Inst(const Inst &) LLVM_DELETED_FUNCTION;
+ Inst &operator=(const Inst &) LLVM_DELETED_FUNCTION;
+};
+
+// Alloca instruction. This captures the size in bytes as getSrc(0),
+// and the required alignment in bytes. The alignment must be either
+// 0 (no alignment required) or a power of 2.
+class InstAlloca : public Inst {
+public:
+ static InstAlloca *create(Cfg *Func, Operand *ByteCount,
+ uint32_t AlignInBytes, Variable *Dest) {
+ return new (Func->allocateInst<InstAlloca>())
+ InstAlloca(Func, ByteCount, AlignInBytes, Dest);
+ }
+ uint32_t getAlignInBytes() const { return AlignInBytes; }
+ Operand *getSizeInBytes() const { return getSrc(0); }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Alloca; }
+
+private:
+ InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes,
+ Variable *Dest);
+ InstAlloca(const InstAlloca &) LLVM_DELETED_FUNCTION;
+ InstAlloca &operator=(const InstAlloca &) LLVM_DELETED_FUNCTION;
+ virtual ~InstAlloca() {}
+ const uint32_t AlignInBytes;
+};
+
+// Binary arithmetic instruction. The source operands are captured in
+// getSrc(0) and getSrc(1).
+class InstArithmetic : public Inst {
+public:
+ enum OpKind {
+#define X(tag, str, commutative) tag,
+ ICEINSTARITHMETIC_TABLE
+#undef X
+ };
+ static InstArithmetic *create(Cfg *Func, OpKind Op, Variable *Dest,
+ Operand *Source1, Operand *Source2) {
+ return new (Func->allocateInst<InstArithmetic>())
+ InstArithmetic(Func, Op, Dest, Source1, Source2);
+ }
+ OpKind getOp() const { return Op; }
+ bool isCommutative() const;
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) {
+ return Inst->getKind() == Arithmetic;
+ }
+
+private:
+ InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1,
+ Operand *Source2);
+ InstArithmetic(const InstArithmetic &) LLVM_DELETED_FUNCTION;
+ InstArithmetic &operator=(const InstArithmetic &) LLVM_DELETED_FUNCTION;
+ virtual ~InstArithmetic() {}
+
+ const OpKind Op;
+};
+
+// Assignment instruction. The source operand is captured in
+// getSrc(0). This is not part of the LLVM bitcode, but is a useful
+// abstraction for some of the lowering. E.g., if Phi instruction
+// lowering happens before target lowering, or for representing an
+// Inttoptr instruction, or as an intermediate step for lowering a
+// Load instruction.
+class InstAssign : public Inst {
+public:
+ static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) {
+ return new (Func->allocateInst<InstAssign>())
+ InstAssign(Func, Dest, Source);
+ }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Assign; }
+
+private:
+ InstAssign(Cfg *Func, Variable *Dest, Operand *Source);
+ InstAssign(const InstAssign &) LLVM_DELETED_FUNCTION;
+ InstAssign &operator=(const InstAssign &) LLVM_DELETED_FUNCTION;
+ virtual ~InstAssign() {}
+};
+
+// Branch instruction. This represents both conditional and
+// unconditional branches.
+class InstBr : public Inst {
+public:
+ // Create a conditional branch. If TargetTrue==TargetFalse, it is
+ // optimized to an unconditional branch.
+ static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue,
+ CfgNode *TargetFalse) {
+ return new (Func->allocateInst<InstBr>())
+ InstBr(Func, Source, TargetTrue, TargetFalse);
+ }
+ // Create an unconditional branch.
+ static InstBr *create(Cfg *Func, CfgNode *Target) {
+ return new (Func->allocateInst<InstBr>()) InstBr(Func, Target);
+ }
+ bool isUnconditional() const { return getTargetTrue() == NULL; }
+ Operand *getCondition() const {
+ assert(!isUnconditional());
+ return getSrc(0);
+ }
+ CfgNode *getTargetTrue() const { return TargetTrue; }
+ CfgNode *getTargetFalse() const { return TargetFalse; }
+ CfgNode *getTargetUnconditional() const {
+ assert(isUnconditional());
+ return getTargetFalse();
+ }
+ virtual NodeList getTerminatorEdges() const;
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Br; }
+
+private:
+ // Conditional branch
+ InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse);
+ // Unconditional branch
+ InstBr(Cfg *Func, CfgNode *Target);
+ InstBr(const InstBr &) LLVM_DELETED_FUNCTION;
+ InstBr &operator=(const InstBr &) LLVM_DELETED_FUNCTION;
+ virtual ~InstBr() {}
+
+ CfgNode *const TargetFalse; // Doubles as unconditional branch target
+ CfgNode *const TargetTrue; // NULL if unconditional branch
+};
+
+// Call instruction. The call target is captured as getSrc(0), and
+// arg I is captured as getSrc(I+1).
+class InstCall : public Inst {
+public:
+ static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest,
+ Operand *CallTarget) {
+ return new (Func->allocateInst<InstCall>())
+ InstCall(Func, NumArgs, Dest, CallTarget);
+ }
+ void addArg(Operand *Arg) { addSource(Arg); }
+ Operand *getCallTarget() const { return getSrc(0); }
+ Operand *getArg(SizeT I) const { return getSrc(I + 1); }
+ SizeT getNumArgs() const { return getSrcSize() - 1; }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Call; }
+
+private:
+ InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget)
+ : Inst(Func, Inst::Call, NumArgs + 1, Dest) {
+ // Set HasSideEffects so that the call instruction can't be
+ // dead-code eliminated. Don't set this for a deletable intrinsic
+ // call.
+ HasSideEffects = true;
+ addSource(CallTarget);
+ }
+ InstCall(const InstCall &) LLVM_DELETED_FUNCTION;
+ InstCall &operator=(const InstCall &) LLVM_DELETED_FUNCTION;
+ virtual ~InstCall() {}
+};
+
+// Cast instruction (a.k.a. conversion operation).
+class InstCast : public Inst {
+public:
+ enum OpKind {
+#define X(tag, str) tag,
+ ICEINSTCAST_TABLE
+#undef X
+ };
+ static InstCast *create(Cfg *Func, OpKind CastKind, Variable *Dest,
+ Operand *Source) {
+ return new (Func->allocateInst<InstCast>())
+ InstCast(Func, CastKind, Dest, Source);
+ }
+ OpKind getCastKind() const { return CastKind; }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Cast; }
+
+private:
+ InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source);
+ InstCast(const InstCast &) LLVM_DELETED_FUNCTION;
+ InstCast &operator=(const InstCast &) LLVM_DELETED_FUNCTION;
+ virtual ~InstCast() {}
+ const OpKind CastKind;
+};
+
+// Floating-point comparison instruction. The source operands are
+// captured in getSrc(0) and getSrc(1).
+class InstFcmp : public Inst {
+public:
+ enum FCond {
+#define X(tag, str) tag,
+ ICEINSTFCMP_TABLE
+#undef X
+ };
+ static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest,
+ Operand *Source1, Operand *Source2) {
+ return new (Func->allocateInst<InstFcmp>())
+ InstFcmp(Func, Condition, Dest, Source1, Source2);
+ }
+ FCond getCondition() const { return Condition; }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Fcmp; }
+
+private:
+ InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1,
+ Operand *Source2);
+ InstFcmp(const InstFcmp &) LLVM_DELETED_FUNCTION;
+ InstFcmp &operator=(const InstFcmp &) LLVM_DELETED_FUNCTION;
+ virtual ~InstFcmp() {}
+ const FCond Condition;
+};
+
+// Integer comparison instruction. The source operands are captured
+// in getSrc(0) and getSrc(1).
+class InstIcmp : public Inst {
+public:
+ enum ICond {
+#define X(tag, str) tag,
+ ICEINSTICMP_TABLE
+#undef X
+ };
+ static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest,
+ Operand *Source1, Operand *Source2) {
+ return new (Func->allocateInst<InstIcmp>())
+ InstIcmp(Func, Condition, Dest, Source1, Source2);
+ }
+ ICond getCondition() const { return Condition; }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Icmp; }
+
+private:
+ InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1,
+ Operand *Source2);
+ InstIcmp(const InstIcmp &) LLVM_DELETED_FUNCTION;
+ InstIcmp &operator=(const InstIcmp &) LLVM_DELETED_FUNCTION;
+ virtual ~InstIcmp() {}
+ const ICond Condition;
+};
+
+// Load instruction. The source address is captured in getSrc(0).
+class InstLoad : public Inst {
+public:
+ static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr) {
+ return new (Func->allocateInst<InstLoad>())
+ InstLoad(Func, Dest, SourceAddr);
+ }
+ Operand *getSourceAddress() const { return getSrc(0); }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Load; }
+
+private:
+ InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr);
+ InstLoad(const InstLoad &) LLVM_DELETED_FUNCTION;
+ InstLoad &operator=(const InstLoad &) LLVM_DELETED_FUNCTION;
+ virtual ~InstLoad() {}
+};
+
+// Phi instruction. For incoming edge I, the node is Labels[I] and
+// the Phi source operand is getSrc(I).
+class InstPhi : public Inst {
+public:
+ static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) {
+ return new (Func->allocateInst<InstPhi>()) InstPhi(Func, MaxSrcs, Dest);
+ }
+ void addArgument(Operand *Source, CfgNode *Label);
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; }
+
+private:
+ InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest);
+ InstPhi(const InstPhi &) LLVM_DELETED_FUNCTION;
+ InstPhi &operator=(const InstPhi &) LLVM_DELETED_FUNCTION;
+ virtual void destroy(Cfg *Func) {
+ Func->deallocateArrayOf<CfgNode *>(Labels);
+ Inst::destroy(Func);
+ }
+ virtual ~InstPhi() {}
+
+ // Labels[] duplicates the InEdges[] information in the enclosing
+ // CfgNode, but the Phi instruction is created before InEdges[]
+ // is available, so it's more complicated to share the list.
+ CfgNode **Labels;
+};
+
+// Ret instruction. The return value is captured in getSrc(0), but if
+// there is no return value (void-type function), then
+// getSrcSize()==0 and hasRetValue()==false.
+class InstRet : public Inst {
+public:
+ static InstRet *create(Cfg *Func, Operand *RetValue = NULL) {
+ return new (Func->allocateInst<InstRet>()) InstRet(Func, RetValue);
+ }
+ bool hasRetValue() const { return getSrcSize(); }
+ Operand *getRetValue() const {
+ assert(hasRetValue());
+ return getSrc(0);
+ }
+ virtual NodeList getTerminatorEdges() const { return NodeList(); }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Ret; }
+
+private:
+ InstRet(Cfg *Func, Operand *RetValue);
+ InstRet(const InstRet &) LLVM_DELETED_FUNCTION;
+ InstRet &operator=(const InstRet &) LLVM_DELETED_FUNCTION;
+ virtual ~InstRet() {}
+};
+
+// Select instruction. The condition, true, and false operands are captured.
+class InstSelect : public Inst {
+public:
+ static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition,
+ Operand *SourceTrue, Operand *SourceFalse) {
+ return new (Func->allocateInst<InstSelect>())
+ InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse);
+ }
+ Operand *getCondition() const { return getSrc(0); }
+ Operand *getTrueOperand() const { return getSrc(1); }
+ Operand *getFalseOperand() const { return getSrc(2); }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Select; }
+
+private:
+ InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1,
+ Operand *Source2);
+ InstSelect(const InstSelect &) LLVM_DELETED_FUNCTION;
+ InstSelect &operator=(const InstSelect &) LLVM_DELETED_FUNCTION;
+ virtual ~InstSelect() {}
+};
+
+// Store instruction. The address operand is captured, along with the
+// data operand to be stored into the address.
+class InstStore : public Inst {
+public:
+ static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr) {
+ return new (Func->allocateInst<InstStore>()) InstStore(Func, Data, Addr);
+ }
+ Operand *getAddr() const { return getSrc(1); }
+ Operand *getData() const { return getSrc(0); }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Store; }
+
+private:
+ InstStore(Cfg *Func, Operand *Data, Operand *Addr);
+ InstStore(const InstStore &) LLVM_DELETED_FUNCTION;
+ InstStore &operator=(const InstStore &) LLVM_DELETED_FUNCTION;
+ virtual ~InstStore() {}
+};
+
+// Switch instruction. The single source operand is captured as
+// getSrc(0).
+class InstSwitch : public Inst {
+public:
+ static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source,
+ CfgNode *LabelDefault) {
+ return new (Func->allocateInst<InstSwitch>())
+ InstSwitch(Func, NumCases, Source, LabelDefault);
+ }
+ Operand *getComparison() const { return getSrc(0); }
+ CfgNode *getLabelDefault() const { return LabelDefault; }
+ SizeT getNumCases() const { return NumCases; }
+ uint64_t getValue(SizeT I) const {
+ assert(I < NumCases);
+ return Values[I];
+ }
+ CfgNode *getLabel(SizeT I) const {
+ assert(I < NumCases);
+ return Labels[I];
+ }
+ void addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label);
+ virtual NodeList getTerminatorEdges() const;
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) { return Inst->getKind() == Switch; }
+
+private:
+ InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault);
+ InstSwitch(const InstSwitch &) LLVM_DELETED_FUNCTION;
+ InstSwitch &operator=(const InstSwitch &) LLVM_DELETED_FUNCTION;
+ virtual void destroy(Cfg *Func) {
+ Func->deallocateArrayOf<uint64_t>(Values);
+ Func->deallocateArrayOf<CfgNode *>(Labels);
+ Inst::destroy(Func);
+ }
+ virtual ~InstSwitch() {}
+
+ CfgNode *LabelDefault;
+ SizeT NumCases; // not including the default case
+ uint64_t *Values; // size is NumCases
+ CfgNode **Labels; // size is NumCases
+};
+
+// Unreachable instruction. This is a terminator instruction with no
+// operands.
+class InstUnreachable : public Inst {
+public:
+ static InstUnreachable *create(Cfg *Func) {
+ return new (Func->allocateInst<InstUnreachable>()) InstUnreachable(Func);
+ }
+ virtual NodeList getTerminatorEdges() const { return NodeList(); }
+ virtual void dump(const Cfg *Func) const;
+ static bool classof(const Inst *Inst) {
+ return Inst->getKind() == Unreachable;
+ }
+
+private:
+ InstUnreachable(Cfg *Func);
+ InstUnreachable(const InstUnreachable &) LLVM_DELETED_FUNCTION;
+ InstUnreachable &operator=(const InstUnreachable &) LLVM_DELETED_FUNCTION;
+ virtual ~InstUnreachable() {}
+};
+
+} // end of namespace Ice
+
+#endif // SUBZERO_SRC_ICEINST_H
« no previous file with comments | « src/IceGlobalContext.cpp ('k') | src/IceInst.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698