/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #ifndef TRANSLATIONENV_H #define TRANSLATIONENV_H #include "ControlNodes.h" #include "LocalEnv.h" struct BasicBlock; struct TranslationCommonEnv: CommonEnv { Pool &primitivePool; // Pool for allocating phi and constant data flow nodes PhiNode *genEmptyPhiNode(const BasicBlock &block, ValueKind kind, Uint32 nExpectedInputs) const; void finishPhiNode(const BasicBlock &block) const; TranslationCommonEnv(Pool &envPool, Pool &primitivePool, Uint32 nLocals, Uint32 stackSize): CommonEnv(envPool, 1, nLocals, stackSize), primitivePool(primitivePool) {} }; class TranslationBinding { public: enum Category { tbNone, // Unknown contents tbSecondWord, // This variable is the second word of a long or double tbConstant, // This variable is a constant constVal defined in basic block definer tbDataEdge, // This variable was defined by the given DataNode tbPhantomPhi, // This variable was defined by the given phantom phi node tbConstantPhi // This variable was defined by the given phantom phi node that always evaluates to a constant }; static bool isPhi(Category c) {return c == tbPhantomPhi || c == tbConstantPhi;} private: struct Constant { const ValueKind kind ENUM_8; // Kind of constant bool producerExists BOOL_8; // If true, a data flow node exists for this constant and can be found //short unused SHORT_16; // using dataNode below. If false, the data flow node can be created union { // in the placeForDataNode control node if needed. ControlNode *placeForDataNode; // Control node inside which the constant was defined DataNode *dataNode; // Link to data flow node that defined this constant }; Value value; // Constant's value Constant(ValueKind kind, ControlNode *placeForDataNode); bool operator==(const Constant &c) const {ValueKind k = kind; return k == c.kind && value.eq(k, c.value);} bool operator!=(const Constant &c) const {ValueKind k = kind; return k != c.kind || !value.eq(k, c.value);} private: void genRealNode(Pool &primitivePool, Uint32 bci); public: bool isNonzero() const {return value.isNonzero(kind);} DataNode &realize(Pool &primitivePool, Uint32 bci); }; class PhantomPhi { const BasicBlock &container; // Block in which this phantom phi node is defined Uint32 nArgs; // Number of occupied arguments in the args array below (valid only when realPhiExists is false) bool realPhiExists BOOL_8; // If true, a real phi node exists and can be found using realPhi below. public: const ValueKind kind ENUM_8; // Kind of value stored in this phi node DEBUG_ONLY(bool duplicate BOOL_8;) // Flag used for assertNoSharedPhantomPhis private: bool alwaysNonzero BOOL_8; // If true, the value of this PhantomPhi is known to always be nonzero union { // (valid only if realPhiExists is false) TranslationBinding *args; // Array of phiSize TranslationBinding records for the arguments of a phantom phi node PhiNode *realPhi; // Real phi node if one has been generated }; PhantomPhi(const PhantomPhi &); // Copying forbidden void operator=(const PhantomPhi &); // Copying forbidden public: PhantomPhi(ValueKind kind, Uint32 size, Uint32 nInitialArgs, const TranslationBinding &initialArgs, const TranslationBinding &arg, const BasicBlock &container, bool alwaysNonzero, Pool &pool); const BasicBlock &getContainer() const {return container;} Uint32 getNArgs() const {assert(!realPhiExists); return nArgs;} bool isAlwaysNonzero() const; void setAlwaysNonzero(bool nz); void append(bool expand, Uint32 newSize, const TranslationBinding &arg, Uint32 bci); private: void genRealPhi(Uint32 bci); public: DataNode &realize(Uint32 bci); }; // A ConstantPhi is a PhantomPhi with the added restriction that all of its arguments are // either the same constant or other ConstantPhis of the same constant. struct ConstantPhi: PhantomPhi { const Constant *constant; // Constant to which all of the arguments of this phantom phi node evaluate ConstantPhi(ValueKind kind, Uint32 size, Uint32 nInitialArgs, const TranslationBinding &initialArgs, const TranslationBinding &arg, const BasicBlock &container, const Constant *constant, Pool &pool); }; Category category ENUM_8; // TranslationBinding category (determines interpretation of union below) //bool unused BOOL_8; //short unused SHORT_16; union { Constant *constant; // Constant value (Constant may be shared among different bindings) DataNode *dataNode; // Place where this variable is defined PhantomPhi *phantomPhi; // Phantom phi node (PhantomPhi may be shared among different bindings) ConstantPhi *constantPhi; // Phantom phi node all of whose arguments evaluate to the same constant (may be shared) void *data; // Used for comparing constNum, constAddr, etc. // Note: The phantomPhi and constantPhi pointers from several different bindings in an environment // may point to a common PhantomPhi or ConstantPhi record under the following circumstances: // 1. phantomPhi->container (or constantPhi->container) is not the current environment's container // 2. All calls to meet and anticipate have completed (at this point sharing can be // introduced, for instance, by assigning one local to another). // Sharing of PhantomPhi or ConstantPhi records in the current environment while meet or // anticipate is running would cause trouble because these routines extend the phantom phi arrays. }; public: bool operator==(const TranslationBinding &b) const {return category == b.category && data == b.data;} bool operator!=(const TranslationBinding &b) const {return category != b.category || data != b.data;} bool isDataEdge() const { return category == tbDataEdge; } bool isSecondWord() const {return category == tbSecondWord;} const Constant *constantValue() const; ValueKind getKind() const; bool isAlwaysNonzero() const; void extract(VariableOrConstant &result, Uint32 bci) const; DataNode &extract(Pool &primitivePool, Uint32 bci) const; DataNode &extract(Uint32 bci) const; void clear(); inline void defineSecondWord(); void defineInt(Int32 v, ControlNode *placeForDataNode, Pool &pool); void defineLong(Int64 v, ControlNode *placeForDataNode, Pool &pool); void defineFloat(Flt32 v, ControlNode *placeForDataNode, Pool &pool); void defineDouble(Flt64 v, ControlNode *placeForDataNode, Pool &pool); void definePtr(addr v, ControlNode *placeForDataNode, Pool &pool); void define(ValueKind kind, const Value &v, ControlNode *placeForDataNode, Pool &pool); void define(DataNode &dataNode); void define(const VariableOrConstant &poc, ControlNode *placeForDataNode, Pool &pool); private: void define(PhantomPhi *p) {category = tbPhantomPhi; phantomPhi = p;} void define(ConstantPhi *p) {category = tbConstantPhi; constantPhi = p;} friend class TranslationEnv; }; class TranslationEnv: public LocalEnv { Uint32 phiSize; // Number of LocalBindings allocated in this environment's phantom phi bindings Uint32 phiOffset; // Next index to be allocated in this environment's phantom phi bindings #ifdef DEBUG bool anticipated; // True if anticipate has been called on this environment #endif public: TranslationEnv(TranslationCommonEnv &commonEnv); TranslationEnv(const TranslationEnv &env); void operator=(const TranslationEnv &env); void move(TranslationEnv &env); Uint32 getPhiSize() const {return phiSize;} const TranslationCommonEnv &getCommonEnv() const {return commonEnv;} #ifdef DEBUG void assertNoSharedPhantomPhis(const BasicBlock &container); #endif void meet(const TranslationEnv &env, bool memoryOnly, const BasicBlock &container); void anticipate(const BasicBlock &container); }; // --- INLINES ---------------------------------------------------------------- // // Initialize a Constant of the given kind. The constant starts out with no // real data flow node, but if one is needed, it will be created in placeForDataNode. // inline TranslationBinding::Constant::Constant(ValueKind kind, ControlNode *placeForDataNode): kind(kind), producerExists(false), placeForDataNode(placeForDataNode) { assert(placeForDataNode); // Prevent this ControlNode from being recycled because a real data flow node could be // created in it at any time. placeForDataNode->inhibitRecycling(); } // // Create if necessary and return a real data flow node for this constant. // Allocate the primitive node out of the given pool. // inline DataNode &TranslationBinding::Constant::realize(Pool &primitivePool, Uint32 bci) { if (!producerExists) genRealNode(primitivePool, bci); return *dataNode; } // // Create if necessary and return the real phi node for this PhantomPhi. // inline DataNode &TranslationBinding::PhantomPhi::realize(Uint32 bci) { if (!realPhiExists) genRealPhi(bci); return *realPhi; } // // Create a new ConstantPhi record with room for size arguments. Ouf of these, // set the first nInitialArgs (which may be zero) to initialArgs, and set the // next argument to arg. Clearly, nInitialArgs must be less than size. // container is the BasicBlock in which this constant phantom phi node is defined. // Every argument of this ConstantPhi must evaluate to constant. // Allocate needed storage from pool. // inline TranslationBinding::ConstantPhi::ConstantPhi(ValueKind kind, Uint32 size, Uint32 nInitialArgs, const TranslationBinding &initialArgs, const TranslationBinding &arg, const BasicBlock &container, const Constant *constant, Pool &pool): PhantomPhi(kind, size, nInitialArgs, initialArgs, arg, container, constant->isNonzero(), pool), constant(constant) {} // // If this TranslationBinding would always evaluate to the same constant, return that // constant; otherwise, return nil. // inline const TranslationBinding::Constant *TranslationBinding::constantValue() const { switch (category) { case tbConstant: return constant; case tbConstantPhi: return constantPhi->constant; default: return 0; } } // // If this TranslationBinding would always evaluate to the same constant, return that // constant in result. Otherwise, return the producer in result, creating phi // nodes for the producer if necessary. // inline void TranslationBinding::extract(VariableOrConstant &result, Uint32 bci) const { const Constant *c; switch (category) { case tbConstant: c = constant; result.setConstant(c->kind, c->value); break; case tbDataEdge: result.setVariable(*dataNode); break; case tbPhantomPhi: result.setVariable(phantomPhi->realize(bci)); break; case tbConstantPhi: c = constantPhi->constant; result.setConstant(c->kind, c->value); break; default: trespass("Can't extract this binding"); } } // // Return the producer for this TranslationBinding, creating phi nodes or // constant nodes if necessary. Create a producer even if it's just a // constant. // inline DataNode & TranslationBinding::extract(Pool &primitivePool, Uint32 bci) const { switch (category) { case tbConstant: return constant->realize(primitivePool, bci); case tbPhantomPhi: case tbConstantPhi: return phantomPhi->realize(bci); case tbDataEdge: return *dataNode; default: trespass("Can't extract this binding"); return *(DataNode *)0; } } // // Return the producer for this TranslationBinding, creating phi nodes if // necessary. It is an error if the producer is a constant. // inline DataNode &TranslationBinding::extract(Uint32 bci) const { switch (category) { case tbPhantomPhi: case tbConstantPhi: return phantomPhi->realize(bci); case tbDataEdge: return *dataNode; default: trespass("Can't extract this binding"); return *(DataNode *)0; } } // // Clear any previous binding from this TranslationBinding. // inline void TranslationBinding::clear() { category = tbNone; data = 0; } // // Bind this TranslationBinding to represent the second word of a long or double. // This TranslationBinding won't carry any more descriptive information about that // long or double -- all such information is carried by the first word's binding. // inline void TranslationBinding::defineSecondWord() { category = tbSecondWord; data = 0; } // // Bind this TranslationBinding to be the result (first word if it's a long or double) // of the given DataNode. // inline void TranslationBinding::define(DataNode &dn) { category = tbDataEdge; dataNode = &dn; } // // Bind this TranslationBinding to be the result (first word if it's a long or double) // of the given DataNode or Constant. // Allocate needed environment storage from pool. // inline void TranslationBinding::define(const VariableOrConstant &poc, ControlNode *placeForDataNode, Pool &pool) { if (poc.isConstant()) define(poc.getKind(), poc.getConstant(), placeForDataNode, pool); else define(poc.getVariable()); } // ---------------------------------------------------------------------------- const Uint32 initialPhiSize = 3; // // Create a new translation binding environment. // The environment starts with one predecessor for the purpose of tracking // the origins of phi nodes' entries. // inline TranslationEnv::TranslationEnv(TranslationCommonEnv &commonEnv): LocalEnv(commonEnv), phiSize(initialPhiSize), phiOffset(1) #ifdef DEBUG , anticipated(false) #endif {} // // Copy a translation binding environment. // The copy starts with one predecessor for the purpose of tracking // the origins of phi nodes' entries. // inline TranslationEnv::TranslationEnv(const TranslationEnv &env): LocalEnv(env), phiSize(initialPhiSize), phiOffset(1) #ifdef DEBUG , anticipated(false) #endif {} // // Assign the given translation binding environment to this one. // The copy starts with one predecessor for the purpose of tracking // the origins of phi nodes' entries. // inline void TranslationEnv::operator=(const TranslationEnv &env) { phiSize = initialPhiSize; phiOffset = 1; #ifdef DEBUG anticipated = false; #endif LocalEnv::operator=(env); } // // Destructively move the given LocalEnv (which must have been initialized) // to this LocalEnv, which must be uninitialized. The given LocalEnv is // left uninitialized. // The moved environment is reset to have only one predecessor for the purpose // of tracking the origins of phi nodes' entries. // inline void TranslationEnv::move(TranslationEnv &env) { phiSize = initialPhiSize; phiOffset = 1; #ifdef DEBUG anticipated = false; #endif LocalEnv::move(env); } #endif