| Index: src/IceOperand.h
|
| diff --git a/src/IceOperand.h b/src/IceOperand.h
|
| index 727ea3da239b9be3c719c6f342bdc410da24f3d8..6a1560f3303332f602e6fb198fc300305dff8d74 100644
|
| --- a/src/IceOperand.h
|
| +++ b/src/IceOperand.h
|
| @@ -385,13 +385,6 @@ public:
|
| void setWeight(uint32_t NewWeight) { Weight = NewWeight; }
|
| void setWeightInfinite() { Weight = RegWeight::Inf; }
|
|
|
| - Variable *getPreferredRegister() const { return RegisterPreference; }
|
| - bool getRegisterOverlap() const { return AllowRegisterOverlap; }
|
| - void setPreferredRegister(Variable *Prefer, bool Overlap) {
|
| - RegisterPreference = Prefer;
|
| - AllowRegisterOverlap = Overlap;
|
| - }
|
| -
|
| const LiveRange &getLiveRange() const { return Live; }
|
| void setLiveRange(const LiveRange &Range) { Live = Range; }
|
| void resetLiveRange() { Live.reset(); }
|
| @@ -416,8 +409,8 @@ public:
|
| // Creates a temporary copy of the variable with a different type.
|
| // Used primarily for syntactic correctness of textual assembly
|
| // emission. Note that only basic information is copied, in
|
| - // particular not DefInst, IsArgument, Weight, RegisterPreference,
|
| - // AllowRegisterOverlap, LoVar, HiVar, VarsReal.
|
| + // particular not DefInst, IsArgument, Weight, LoVar, HiVar,
|
| + // VarsReal.
|
| Variable asType(Type Ty);
|
|
|
| virtual void emit(const Cfg *Func) const;
|
| @@ -436,8 +429,7 @@ protected:
|
| Variable(OperandKind K, Type Ty, SizeT Index, const IceString &Name)
|
| : Operand(K, Ty), Number(Index), Name(Name), IsArgument(false),
|
| IsImplicitArgument(false), StackOffset(0), RegNum(NoRegister),
|
| - RegNumTmp(NoRegister), Weight(1), RegisterPreference(NULL),
|
| - AllowRegisterOverlap(false), LoVar(NULL), HiVar(NULL) {
|
| + RegNumTmp(NoRegister), Weight(1), LoVar(NULL), HiVar(NULL) {
|
| Vars = VarsReal;
|
| Vars[0] = this;
|
| NumVars = 1;
|
| @@ -450,7 +442,7 @@ protected:
|
| bool IsArgument;
|
| bool IsImplicitArgument;
|
| // StackOffset is the canonical location on stack (only if
|
| - // RegNum<0 || IsArgument).
|
| + // RegNum==NoRegister || IsArgument).
|
| int32_t StackOffset;
|
| // RegNum is the allocated register, or NoRegister if it isn't
|
| // register-allocated.
|
| @@ -458,16 +450,6 @@ protected:
|
| // RegNumTmp is the tentative assignment during register allocation.
|
| int32_t RegNumTmp;
|
| RegWeight Weight; // Register allocation priority
|
| - // RegisterPreference says that if possible, the register allocator
|
| - // should prefer the register that was assigned to this linked
|
| - // variable. It also allows a spill slot to share its stack
|
| - // location with another variable, if that variable does not get
|
| - // register-allocated and therefore has a stack location.
|
| - Variable *RegisterPreference;
|
| - // AllowRegisterOverlap says that it is OK to honor
|
| - // RegisterPreference and "share" a register even if the two live
|
| - // ranges overlap.
|
| - bool AllowRegisterOverlap;
|
| LiveRange Live;
|
| // LoVar and HiVar are needed for lowering from 64 to 32 bits. When
|
| // lowering from I64 to I32 on a 32-bit architecture, we split the
|
| @@ -483,14 +465,18 @@ protected:
|
| Variable *VarsReal[1];
|
| };
|
|
|
| -// VariableTracking tracks the metadata for a single variable.
|
| +typedef std::vector<const Inst *> InstDefList;
|
| +
|
| +// VariableTracking tracks the metadata for a single variable. It is
|
| +// only meant to be used internally by VariablesMetadata.
|
| class VariableTracking {
|
| public:
|
| enum MultiDefState {
|
| // TODO(stichnot): Consider using just a simple counter.
|
| MDS_Unknown,
|
| MDS_SingleDef,
|
| - MDS_MultiDef
|
| + MDS_MultiDefSingleBlock,
|
| + MDS_MultiDefMultiBlock
|
| };
|
| enum MultiBlockState {
|
| MBS_Unknown,
|
| @@ -499,10 +485,12 @@ public:
|
| };
|
| VariableTracking()
|
| : MultiDef(MDS_Unknown), MultiBlock(MBS_Unknown), SingleUseNode(NULL),
|
| - SingleDefInst(NULL) {}
|
| + SingleDefNode(NULL) {}
|
| MultiDefState getMultiDef() const { return MultiDef; }
|
| MultiBlockState getMultiBlock() const { return MultiBlock; }
|
| - const Inst *getDefinition() const { return SingleDefInst; }
|
| + const Inst *getFirstDefinition() const;
|
| + const Inst *getSingleDefinition() const;
|
| + const InstDefList &getDefinitions() const { return Definitions; }
|
| const CfgNode *getNode() const { return SingleUseNode; }
|
| void markUse(const Inst *Instr, const CfgNode *Node, bool IsFromDef,
|
| bool IsImplicit);
|
| @@ -513,7 +501,12 @@ private:
|
| MultiDefState MultiDef;
|
| MultiBlockState MultiBlock;
|
| const CfgNode *SingleUseNode;
|
| - const Inst *SingleDefInst;
|
| + const CfgNode *SingleDefNode;
|
| + // All definitions of the variable are collected here, in the order
|
| + // encountered. Definitions in the same basic block are in
|
| + // instruction order, but there's no guarantee for the basic block
|
| + // order.
|
| + InstDefList Definitions;
|
| };
|
|
|
| // VariablesMetadata analyzes and summarizes the metadata for the
|
| @@ -521,18 +514,50 @@ private:
|
| class VariablesMetadata {
|
| public:
|
| VariablesMetadata(const Cfg *Func) : Func(Func) {}
|
| + // Initialize the state by traversing all instructions/variables in
|
| + // the CFG.
|
| void init();
|
| + // Returns whether the given Variable is tracked in this object. It
|
| + // should only return false if changes were made to the CFG after
|
| + // running init(), in which case the state is stale and the results
|
| + // shouldn't be trusted (but it may be OK e.g. for dumping).
|
| bool isTracked(const Variable *Var) const {
|
| return Var->getIndex() < Metadata.size();
|
| }
|
| +
|
| + // Returns whether the given Variable has multiple definitions.
|
| bool isMultiDef(const Variable *Var) const;
|
| - const Inst *getDefinition(const Variable *Var) const;
|
| + // Returns the first definition instruction of the given Variable.
|
| + // This is only valid for variables whose definitions are all within
|
| + // the same block, e.g. T after the lowered sequence "T=B; T+=C;
|
| + // A=T", for which getFirstDefinition(T) would return the "T=B"
|
| + // instruction. For variables with definitions span multiple
|
| + // blocks, NULL is returned.
|
| + const Inst *getFirstDefinition(const Variable *Var) const;
|
| + // Returns the definition instruction of the given Variable, when
|
| + // the variable has exactly one definition. Otherwise, NULL is
|
| + // returned.
|
| + const Inst *getSingleDefinition(const Variable *Var) const;
|
| + // Returns the list of all definition instructions of the given
|
| + // Variable.
|
| + const InstDefList &getDefinitions(const Variable *Var) const;
|
| +
|
| + // Returns whether the given Variable is live across multiple
|
| + // blocks. Mainly, this is used to partition Variables into
|
| + // single-block versus multi-block sets for leveraging sparsity in
|
| + // liveness analysis, and for implementing simple stack slot
|
| + // coalescing. As a special case, function arguments are always
|
| + // considered multi-block because they are live coming into the
|
| + // entry block.
|
| bool isMultiBlock(const Variable *Var) const;
|
| + // Returns the node that the given Variable is used in, assuming
|
| + // isMultiBlock() returns false. Otherwise, NULL is returned.
|
| const CfgNode *getLocalUseNode(const Variable *Var) const;
|
|
|
| private:
|
| const Cfg *Func;
|
| std::vector<VariableTracking> Metadata;
|
| + const static InstDefList NoDefinitions;
|
| VariablesMetadata(const VariablesMetadata &) LLVM_DELETED_FUNCTION;
|
| VariablesMetadata &operator=(const VariablesMetadata &) LLVM_DELETED_FUNCTION;
|
| };
|
|
|