/* -*- 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 PRIMITIVEBUILDERS_H #define PRIMITIVEBUILDERS_H #include "ControlGraph.h" #include "SysCalls.h" struct Signature; struct UnaryBuilder { virtual Primitive *makeUnaryGeneric(const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *container) const = 0; }; class UnaryGenericBuilder: public UnaryBuilder { protected: const PrimitiveOperation op; // Kind of primitive operation Primitive *makeOneProducerGeneric(const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *container) const; public: UnaryGenericBuilder(PrimitiveOperation op): op(op) {} }; struct BinaryBuilder { virtual Primitive *makeBinaryGeneric(const VariableOrConstant *args, VariableOrConstant &result, ControlNode *container) const = 0; }; class BinaryGenericBuilder: public BinaryBuilder { protected: const PrimitiveOperation op; // Kind of primitive operation virtual Primitive *makeTwoProducerGeneric(const VariableOrConstant *args, VariableOrConstant &result, ControlNode *container) const; public: BinaryGenericBuilder(PrimitiveOperation op): op(op) {} }; // ---------------------------------------------------------------------------- // NegBuilder // Builder of negations template struct NegBuilder: UnaryBuilder { Primitive *makeUnaryGeneric(const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *container) const; }; extern const NegBuilder builder_Neg_II; extern const NegBuilder builder_Neg_LL; extern const NegBuilder builder_Neg_FF; extern const NegBuilder builder_Neg_DD; // ---------------------------------------------------------------------------- // ConvBuilder // Builder of numeric conversions template struct ConvBuilder: UnaryGenericBuilder { Primitive *makeUnaryGeneric(const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *container) const; ConvBuilder(PrimitiveOperation op): UnaryGenericBuilder(op) {} }; extern const ConvBuilder builder_Conv_IL; extern const ConvBuilder builder_Conv_IF; extern const ConvBuilder builder_Conv_ID; extern const ConvBuilder builder_Conv_LI; extern const ConvBuilder builder_Conv_LF; extern const ConvBuilder builder_Conv_LD; extern const ConvBuilder builder_Conv_FI; extern const ConvBuilder builder_Conv_FL; extern const ConvBuilder builder_Conv_FD; extern const ConvBuilder builder_Conv_DI; extern const ConvBuilder builder_Conv_DL; extern const ConvBuilder builder_Conv_DF; // ---------------------------------------------------------------------------- // ExtBuilder // Builder of integer bit field extractions struct ExtBuilder: UnaryBuilder { const bool isSigned; // True indicates the bit field is signed const int width; // Width of the right-justified bit field (between 1 and 31) Primitive *makeUnaryGeneric(const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *container) const; ExtBuilder(bool isSigned, int width): isSigned(isSigned), width(width) {} }; extern const ExtBuilder builder_ExtB_II; extern const ExtBuilder builder_ExtC_II; extern const ExtBuilder builder_ExtS_II; // ---------------------------------------------------------------------------- // BinarySpecializedBuilder template struct BinarySpecializedBuilder: BinaryGenericBuilder { virtual void evaluate(T1 arg1, T2 arg2, TR &result) const = 0; Primitive *specializeConstConst(T1 arg1, T2 arg2, VariableOrConstant &result) const; virtual Primitive *specializeConstVar(T1 arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; virtual Primitive *specializeVarConst(DataNode &arg1, T2 arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeConstArg(T1 arg1, const VariableOrConstant &arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeArgConst(const VariableOrConstant &arg1, T2 arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *makeBinaryGeneric(const VariableOrConstant *args, VariableOrConstant &result, ControlNode *container) const; BinarySpecializedBuilder(PrimitiveOperation op): BinaryGenericBuilder(op) {} }; // // Allocate or evaluate the primitive with the two given arguments, both of which // are constants. The result will be a constant as well. // Return the last new primitive that generates the result or 0 if none (when the // result is a constant or copied directly from one of the arguments). // template inline Primitive *BinarySpecializedBuilder::specializeConstConst(T1 arg1, T2 arg2, VariableOrConstant &result) const { TR res; evaluate(arg1, arg2, res); result.setConstant(res); return 0; } // // Allocate or evaluate the primitive with the two given arguments, the first of which // is a constant and the second either a constant or a variable. // Return the last new primitive that generates the result or 0 if none (when the // result is a constant or copied directly from one of the arguments). // template inline Primitive *BinarySpecializedBuilder::specializeConstArg(T1 arg1, const VariableOrConstant &arg2, VariableOrConstant &result, ControlNode *container) const { assert(arg2.hasKind(TypeValueKind(T2))); Primitive *prim; if (arg2.isConstant()) prim = specializeConstConst(arg1, arg2.getConstant().TypeGetValueContents(T2), result); else prim = specializeConstVar(arg1, arg2.getVariable(), result, container); assert(result.hasKind(TypeValueKind(TR))); return prim; } // // Allocate or evaluate the primitive with the two given arguments, the second of which // is a constant and the first either a constant or a variable. // Return the last new primitive that generates the result or 0 if none (when the // result is a constant or copied directly from one of the arguments). // template inline Primitive *BinarySpecializedBuilder::specializeArgConst(const VariableOrConstant &arg1, T2 arg2, VariableOrConstant &result, ControlNode *container) const { assert(arg1.hasKind(TypeValueKind(T1))); Primitive *prim; if (arg1.isConstant()) prim = specializeConstConst(arg1.getConstant().TypeGetValueContents(T1), arg2, result); else prim = specializeVarConst(arg1.getVariable(), arg2, result, container); assert(result.hasKind(TypeValueKind(TR))); return prim; } // ---------------------------------------------------------------------------- // CommutativeBuilder // Builder of commutative operations template struct CommutativeBuilder: BinarySpecializedBuilder { Primitive *specializeConstVar(TA arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; CommutativeBuilder(PrimitiveOperation op): BinarySpecializedBuilder(op) {} }; // ---------------------------------------------------------------------------- // AddBuilder // Builder of homogeneous additions template struct AddBuilder: CommutativeBuilder { const bool coalesce; // If true, this add may be coalesced with an add in one of the arguments void evaluate(T arg1, T arg2, T &result) const; Primitive *specializeVarConst(DataNode &arg1, T arg2, VariableOrConstant &result, ControlNode *container) const; AddBuilder(PrimitiveOperation op, bool coalesce): CommutativeBuilder(op), coalesce(coalesce) {} }; extern const AddBuilder builder_Add_III; extern const AddBuilder builder_Add_LLL; extern const AddBuilder builder_Add_FFF; extern const AddBuilder builder_Add_DDD; // Coalescing versions of the above; these automatically convert expressions // like (x+c)+d where c and d are constants into x+(c+d). extern const AddBuilder builder_AddCoal_III; extern const AddBuilder builder_AddCoal_LLL; // Coalescing is not available for floating point because floating point addition // is not associative. inline const AddBuilder &getAddBuilder(Int32, bool coalesce) {return coalesce ? builder_AddCoal_III : builder_Add_III;} inline const AddBuilder &getAddBuilder(Int64, bool coalesce) {return coalesce ? builder_AddCoal_LLL : builder_Add_LLL;} inline const AddBuilder &getAddBuilder(Flt32, bool) {return builder_Add_FFF;} inline const AddBuilder &getAddBuilder(Flt64, bool) {return builder_Add_DDD;} #define TypeGetAddBuilder(T, coalesce) getAddBuilder((T)0, coalesce) // ---------------------------------------------------------------------------- // AddABuilder // Builder of pointer additions struct AddABuilder: BinarySpecializedBuilder { const bool coalesce; // If true, this add may be coalesced with an add in one of the arguments void evaluate(addr arg1, Int32 arg2, addr &result) const; Primitive *specializeConstVar(addr arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeVarConst(DataNode &arg1, Int32 arg2, VariableOrConstant &result, ControlNode *container) const; explicit AddABuilder(bool coalesce): BinarySpecializedBuilder(poAdd_A), coalesce(coalesce) {} }; extern const AddABuilder builder_Add_AIA; // Coalescing version of the above; this automatically converts expressions // like (x+c)+d where c and d are constants into x+(c+d). extern const AddABuilder builder_AddCoal_AIA; // ---------------------------------------------------------------------------- // SubBuilder // Builder of homogeneous subtractions template struct SubBuilder: BinarySpecializedBuilder { const bool coalesce; // If true, this add may be coalesced with an add in one of the arguments void evaluate(T arg1, T arg2, T &result) const; Primitive *specializeConstVar(T arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeVarConst(DataNode &arg1, T arg2, VariableOrConstant &result, ControlNode *container) const; SubBuilder(PrimitiveOperation op, bool coalesce): BinarySpecializedBuilder(op), coalesce(coalesce) {} }; extern const SubBuilder builder_Sub_III; extern const SubBuilder builder_Sub_LLL; extern const SubBuilder builder_Sub_FFF; extern const SubBuilder builder_Sub_DDD; // Coalescing versions of the above; these automatically convert expressions // like (x-c)-d where c and d are constants into x-(c+d). extern const SubBuilder builder_SubCoal_III; extern const SubBuilder builder_SubCoal_LLL; // Coalescing is not available for floating point because floating point addition // is not associative. inline const SubBuilder &getSubBuilder(Int32) {return builder_Sub_III;} inline const SubBuilder &getSubBuilder(Int64) {return builder_Sub_LLL;} inline const SubBuilder &getSubBuilder(Flt32) {return builder_Sub_FFF;} inline const SubBuilder &getSubBuilder(Flt64) {return builder_Sub_DDD;} #define TypeGetSubBuilder(T) getSubBuilder((T)0) // ---------------------------------------------------------------------------- // MulBuilder // Builder of homogeneous multiplications template struct MulBuilder: CommutativeBuilder { void evaluate(T arg1, T arg2, T &result) const; Primitive *specializeVarConst(DataNode &arg1, T arg2, VariableOrConstant &result, ControlNode *container) const; MulBuilder(PrimitiveOperation op): CommutativeBuilder(op) {} }; extern const MulBuilder builder_Mul_III; extern const MulBuilder builder_Mul_LLL; extern const MulBuilder builder_Mul_FFF; extern const MulBuilder builder_Mul_DDD; // ---------------------------------------------------------------------------- // DivModBuilder // Builder of integer divisions and modulos class DivModBuilder: public BinaryBuilder { const BinaryBuilder &generalBuilder; // Builder to use when we don't know whether the divisor is zero const BinaryBuilder &nonZeroBuilder; // Builder to use when we know that the divisor is nonzero public: Primitive *makeBinaryGeneric(const VariableOrConstant *args, VariableOrConstant &result, ControlNode *container) const; DivModBuilder(const BinaryBuilder &generalBuilder, const BinaryBuilder &nonZeroBuilder): generalBuilder(generalBuilder), nonZeroBuilder(nonZeroBuilder) {} }; extern const DivModBuilder builder_Div_III; extern const DivModBuilder builder_Div_LLL; extern const DivModBuilder builder_Mod_III; extern const DivModBuilder builder_Mod_LLL; // ---------------------------------------------------------------------------- // FDivBuilder // Builder of floating point divisions template struct FDivBuilder: BinarySpecializedBuilder { void evaluate(T arg1, T arg2, T &result) const; Primitive *specializeConstVar(T arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeVarConst(DataNode &arg1, T arg2, VariableOrConstant &result, ControlNode *container) const; FDivBuilder(PrimitiveOperation op): BinarySpecializedBuilder(op) {} }; extern const FDivBuilder builder_Div_FFF; extern const FDivBuilder builder_Div_DDD; // ---------------------------------------------------------------------------- // FRemBuilder // Builder of floating point remainders template struct FRemBuilder: BinarySpecializedBuilder { void evaluate(T arg1, T arg2, T &result) const; Primitive *specializeConstVar(T arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeVarConst(DataNode &arg1, T arg2, VariableOrConstant &result, ControlNode *container) const; FRemBuilder(PrimitiveOperation op): BinarySpecializedBuilder(op) {} }; extern const FRemBuilder builder_Rem_FFF; extern const FRemBuilder builder_Rem_DDD; // ---------------------------------------------------------------------------- // ShiftBuilder // Builder of arithmetic and logical shifts enum ShiftDir {sdLeft, sdRightArithmetic, sdRightLogical, sdSignedExtract}; template struct ShiftBuilder: BinarySpecializedBuilder { const ShiftDir shiftDir; void evaluate(T arg1, Int32 arg2, T &result) const; Primitive *specializeConstVar(T arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeVarConst(DataNode &arg1, Int32 arg2, VariableOrConstant &result, ControlNode *container) const; ShiftBuilder(PrimitiveOperation op, ShiftDir shiftDir); }; extern const ShiftBuilder builder_Shl_III; extern const ShiftBuilder builder_Shl_LIL; extern const ShiftBuilder builder_Shr_III; extern const ShiftBuilder builder_Shr_LIL; extern const ShiftBuilder builder_UShr_III; extern const ShiftBuilder builder_UShr_LIL; extern const ShiftBuilder builder_Ext_III; extern const ShiftBuilder builder_Ext_LIL; // ---------------------------------------------------------------------------- // LogicalBuilder // Builder of homogeneous logical operations enum LogicalOp {loAnd, loOr, loXor}; template struct LogicalBuilder: CommutativeBuilder { const LogicalOp logicalOp; // The logical operation op that this builder builds const T identity; // A value i such that for all x: x op i, i op x, and x are all equal. const T annihilator; // A value a such that for all x: x op a, a op x, and a are all equal. // If there is no such a, set annihilator to the same value as identity. void evaluate(T arg1, T arg2, T &result) const; Primitive *specializeVarConst(DataNode &arg1, T arg2, VariableOrConstant &result, ControlNode *container) const; LogicalBuilder(PrimitiveOperation op, LogicalOp logicalOp, T identity, T annihilator); }; extern const LogicalBuilder builder_And_III; extern const LogicalBuilder builder_And_LLL; extern const LogicalBuilder builder_Or_III; extern const LogicalBuilder builder_Or_LLL; extern const LogicalBuilder builder_Xor_III; extern const LogicalBuilder builder_Xor_LLL; // ---------------------------------------------------------------------------- // ComparisonBuilder // Builder of two-argument comparisons template struct ComparisonBuilder: BinarySpecializedBuilder { const bool isUnsigned; // Is the comparison unsigned? const bool equalityOnly; // Do we only care about equality/inequality? void evaluate(T arg1, T arg2, Condition &result) const; Primitive *specializeConstVar(T arg1, DataNode &arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *specializeVarConst(DataNode &arg1, T arg2, VariableOrConstant &result, ControlNode *container) const; Primitive *makeTwoProducerGeneric(const VariableOrConstant *args, VariableOrConstant &result, ControlNode *container) const; ComparisonBuilder(PrimitiveOperation op, bool isUnsigned, bool equalityOnly); }; extern const ComparisonBuilder builder_Cmp_IIC; extern const ComparisonBuilder builder_Cmp_LLC; extern const ComparisonBuilder builder_Cmp_FFC; extern const ComparisonBuilder builder_Cmp_DDC; extern const ComparisonBuilder builder_CmpU_IIC; extern const ComparisonBuilder builder_CmpU_AAC; // Same as Cmp or CmpU except that the comparison only compares for equality // so the resulting condition is always either cEq or cUn; these may be slightly // faster than Cmp or CmpU when they do apply. extern const ComparisonBuilder builder_CmpEq_IIC; extern const ComparisonBuilder builder_CmpUEq_AAC; // ---------------------------------------------------------------------------- // Cond2Builder // Builder of two-argument two-way conditionals that yield an integer class Cond2Builder: public BinaryBuilder { const PrimitiveOperation opNormal ENUM_16; // Kind of condition primitive when the comparison is done normally const PrimitiveOperation opReverse ENUM_16; // Kind of condition primitive when the comparison's arguments are reversed const BinaryBuilder &comparer; // Builder of the comparison public: Primitive *makeBinaryGeneric(const VariableOrConstant *args, VariableOrConstant &result, ControlNode *container) const; Cond2Builder(PrimitiveOperation opNormal, PrimitiveOperation opReverse, const BinaryBuilder &comparer); }; extern const Cond2Builder builder_Eq_III; extern const Cond2Builder builder_Ne_III; extern const Cond2Builder builder_Lt_III; extern const Cond2Builder builder_Ge_III; extern const Cond2Builder builder_Gt_III; extern const Cond2Builder builder_Le_III; extern const Cond2Builder builder_LtU_III; extern const Cond2Builder builder_GeU_III; extern const Cond2Builder builder_GtU_III; extern const Cond2Builder builder_LeU_III; extern const Cond2Builder builder_Eq_AAI; extern const Cond2Builder builder_Ne_AAI; // ---------------------------------------------------------------------------- // Cond3Builder // Builder of two-argument three-way conditionals that yield an integer class Cond3Builder: public BinaryBuilder { const PrimitiveOperation opNormal ENUM_16; // Kind of condition primitive when the comparison is done normally const PrimitiveOperation opReverse ENUM_16; // Kind of condition primitive when the comparison's arguments are reversed const BinaryBuilder &comparer; // Builder of the comparison public: Primitive *makeBinaryGeneric(const VariableOrConstant *args, VariableOrConstant &result, ControlNode *container) const; Cond3Builder(PrimitiveOperation opNormal, PrimitiveOperation opReverse, const BinaryBuilder &comparer); }; extern const Cond3Builder builder_Cmp3_LLI; extern const Cond3Builder builder_Cmp3L_FFI; extern const Cond3Builder builder_Cmp3G_FFI; extern const Cond3Builder builder_Cmp3L_DDI; extern const Cond3Builder builder_Cmp3G_DDI; // ---------------------------------------------------------------------------- // TestBuilder // Builder of one-argument three-way and two-way comparisons against zero template class TestBuilder: public UnaryBuilder { const BinaryBuilder &condBuilder; // Two-argument version of the same comparison public: Primitive *makeUnaryGeneric(const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *container) const; explicit TestBuilder(const BinaryBuilder &condBuilder); }; extern const TestBuilder builder_Eq0_II; extern const TestBuilder builder_Ne0_II; extern const TestBuilder builder_Lt0_II; extern const TestBuilder builder_Ge0_II; extern const TestBuilder builder_Gt0_II; extern const TestBuilder builder_Le0_II; extern const TestBuilder builder_Eq0_AI; extern const TestBuilder builder_Ne0_AI; // ---------------------------------------------------------------------------- // Check primitive builders enum CheckResult {chkAlwaysOK, chkNeverOK, chkMaybeOK}; CheckResult makeChkNull(const VariableOrConstant &arg, Primitive *&prim, ControlNode *container, Uint32 bci); CheckResult makeLimit(const VariableOrConstant &arg1, const VariableOrConstant &arg2, Primitive *&prim, ControlNode *container); Primitive *makeChkCastI(DataNode &arg1, DataNode &arg2, ControlNode *container); Primitive *makeChkCastA(DataNode &dp, const Type &type, ControlNode *container); CheckResult makeLimCast(const VariableOrConstant &arg1, Int32 limit, Primitive *&prim, ControlNode *container); // ---------------------------------------------------------------------------- // LoadBuilder // Builder of memory loads class LoadBuilder { const PrimitiveOperation op ENUM_16; // Kind of load primitive const TypeKind outputType ENUM_8; // The type of the value that we're loading PrimLoad *createLoad(PrimitiveOperation op, DataNode **memory, VariableOrConstant &result, bool isVolatile, bool isConstant, ControlNode *container, Uint32 bci) const; public: void makeLoad(DataNode **memory, addr address, VariableOrConstant &result, bool isVolatile, bool isConstant, ControlNode *container, Uint32 bci) const; void makeLoad(DataNode **memory, const VariableOrConstant &address, VariableOrConstant &result, bool isVolatile, bool isConstant, ControlNode *container, Uint32 bci) const; LoadBuilder(PrimitiveOperation op, TypeKind outputType); }; extern const LoadBuilder builder_Ld_AI; extern const LoadBuilder builder_Ld_AL; extern const LoadBuilder builder_Ld_AF; extern const LoadBuilder builder_Ld_AD; extern const LoadBuilder builder_Ld_AA; extern const LoadBuilder builder_LdS_AB; extern const LoadBuilder builder_LdS_AH; extern const LoadBuilder builder_LdU_AB; extern const LoadBuilder builder_LdU_AH; // ---------------------------------------------------------------------------- // StoreBuilder // Builder of memory stores class StoreBuilder { const PrimitiveOperation opPure ENUM_16; // Kind of store primitive when the arguments are variables const ValueKind inputKind ENUM_8; // The kind of the value that we're storing public: Primitive &makeStore(DataNode &memoryIn, const VariableOrConstant &address, const VariableOrConstant &value, bool isVolatile, ControlNode *container, Uint32 bci) const; StoreBuilder(PrimitiveOperation opPure, ValueKind inputKind); }; extern const StoreBuilder builder_St_AB; extern const StoreBuilder builder_St_AH; extern const StoreBuilder builder_St_AI; extern const StoreBuilder builder_St_AL; extern const StoreBuilder builder_St_AF; extern const StoreBuilder builder_St_AD; extern const StoreBuilder builder_St_AA; // ---------------------------------------------------------------------------- // Monitor primitive builders Primitive &makeMonitorPrimitive(PrimitiveOperation op, DataNode &memoryIn, const VariableOrConstant &arg, Uint32 slot, ControlNode *container, Uint32 bci); // ---------------------------------------------------------------------------- // Call builders // Use the checked inline version below instead of this makeSysCall. Primitive &makeSysCall(const SysCall &sysCall, DataNode **memory, const VariableOrConstant *args, VariableOrConstant *results, ControlNode &container, Uint32 bci); inline Primitive &makeSysCall(const SysCall &sysCall, DataNode **memory, uint DEBUG_ONLY(nArgs), const VariableOrConstant *args, uint DEBUG_ONLY(nResults), VariableOrConstant *results, ControlNode &container, Uint32 bci) { assert(nArgs == sysCall.nInputs - sysCall.hasMemoryInput() && nResults == sysCall.nOutputs - sysCall.hasMemoryOutput() && sysCall.hasMemoryInput() == (memory != 0) && sysCall.hasMemoryOutput() == (memory != 0)); return makeSysCall(sysCall, memory, args, results, container, bci); } Primitive &makeCall(const Signature &sig, DataNode *&memory, const VariableOrConstant &function, const Method *method, const VariableOrConstant *args, VariableOrConstant *results, ControlNode &container, Uint32 bci); #endif