Path: blob/master/runtime/compiler/z/codegen/J9CodeGenerator.hpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#ifndef J9_Z_CODEGENERATOR_INCL23#define J9_Z_CODEGENERATOR_INCL2425/*26* The following #define and typedef must appear before any #includes in this file27*/28#ifndef J9_CODEGENERATOR_CONNECTOR29#define J9_CODEGENERATOR_CONNECTOR30namespace J9 { namespace Z { class CodeGenerator; } }31namespace J9 { typedef J9::Z::CodeGenerator CodeGeneratorConnector; }32#else33#error J9::Z::CodeGenerator expected to be a primary connector, but a J9 connector is already defined34#endif3536#include "compiler/codegen/J9CodeGenerator.hpp"37#include "j9cfg.h"3839namespace TR { class S390EyeCatcherDataSnippet; }40namespace TR { class Node; }414243namespace J944{4546namespace Z47{4849class OMR_EXTENSIBLE CodeGenerator : public J9::CodeGenerator50{5152protected:5354CodeGenerator(TR::Compilation *comp);5556public:5758void initialize();5960TR::Recompilation *allocateRecompilationInfo();6162bool doInlineAllocate(TR::Node *node);6364TR::Linkage *createLinkage(TR_LinkageConventions lc);6566void lowerTreesPreChildrenVisit(TR::Node * parent, TR::TreeTop * treeTop, vcount_t visitCount);67void lowerTreesPostChildrenVisit(TR::Node * parent, TR::TreeTop * treeTop, vcount_t visitCount);6869void lowerTreeIfNeeded(TR::Node *node, int32_t childNumber, TR::Node *parent, TR::TreeTop *tt);7071TR::S390EyeCatcherDataSnippet *CreateEyeCatcher(TR::Node *);7273void genZeroLeftMostUnicodeBytes(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, int32_t bytesToClear, TR::MemoryReference *targetMR);74void widenZonedSignLeadingEmbedded(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, int32_t bytesToClear, TR::MemoryReference *targetMR);75void widenUnicodeSignLeadingSeparate(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, int32_t bytesToClear, TR::MemoryReference *targetMR);76void widenZonedSignLeadingSeparate(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, int32_t bytesToClear, TR::MemoryReference *targetMR);77void genZeroLeftMostZonedBytes(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, int32_t bytesToClear, TR::MemoryReference *targetMR);7879bool alwaysGeneratesAKnownCleanSign(TR::Node *node);80bool alwaysGeneratesAKnownPositiveCleanSign(TR::Node *node);81bool canUseRelativeLongInstructions(int64_t value);82TR_RawBCDSignCode alwaysGeneratedSign(TR::Node *node);8384uint32_t getPDMulEncodedSize(TR::Node *pdmul, TR_PseudoRegister *multiplicand, TR_PseudoRegister *multiplier);85uint32_t getPDMulEncodedSize(TR::Node *pdmul);86uint32_t getPDMulEncodedSize(TR::Node *pdmul, int32_t exponent);87int32_t getPDMulEncodedPrecision(TR::Node *pdmul, TR_PseudoRegister *multiplicand, TR_PseudoRegister *multiplier);88int32_t getPDMulEncodedPrecision(TR::Node *pdmul);89int32_t getPDMulEncodedPrecision(TR::Node *pdmul, int32_t exponent);90bool callUsesHelperImplementation(TR::Symbol *sym);9192uint32_t getLongToPackedFixedSize() { return TR_LONG_TO_PACKED_SIZE; }93uint32_t getIntegerToPackedFixedSize() { return TR_INTEGER_TO_PACKED_SIZE; }94uint32_t getPackedToLongFixedSize() { return TR_PACKED_TO_LONG_SIZE; }95uint32_t getPackedToIntegerFixedSize() { return TR_PACKED_TO_INTEGER_SIZE; }96uint32_t getPackedToUnicodeFixedSourceSize() { return TR_PACKED_TO_UNICODE_SOURCE_SIZE; }97uint32_t getUnicodeToPackedFixedResultSize() { return TR_UNICODE_TO_PACKED_RESULT_SIZE; }98uint32_t getAsciiToPackedFixedResultSize() { return TR_ASCII_TO_PACKED_RESULT_SIZE; }99uint32_t getPDDivEncodedSize(TR::Node *node);100uint32_t getPDDivEncodedSize(TR::Node *node, TR_PseudoRegister *dividendReg, TR_PseudoRegister *divisorReg);101uint32_t getPDAddSubEncodedSize(TR::Node *node);102uint32_t getPDAddSubEncodedSize(TR::Node *node, TR_PseudoRegister *firstReg);103int32_t getPDAddSubEncodedPrecision(TR::Node *node);104int32_t getPDAddSubEncodedPrecision(TR::Node *node, TR_PseudoRegister *firstReg);105int32_t getPDDivEncodedPrecisionCommon(TR::Node *node, int32_t dividendPrecision, int32_t divisorPrecision, bool isDivisorEvenPrecision);106int32_t getPDDivEncodedPrecision(TR::Node *node);107int32_t getPDDivEncodedPrecision(TR::Node *node, TR_PseudoRegister *dividendReg, TR_PseudoRegister *divisorReg);108109bool supportsPackedShiftRight(int32_t resultPrecision, TR::Node *shiftSource, int32_t shiftAmount);110bool canGeneratePDBinaryIntrinsic(TR::ILOpCodes opCode, TR::Node * op1PrecNode, TR::Node * op2PrecNode, TR::Node * resultPrecNode);111112bool constLoadNeedsLiteralFromPool(TR::Node *node);113114bool supportsTrapsInTMRegion();115116using J9::CodeGenerator::addAllocatedRegister;117void addAllocatedRegister(TR_PseudoRegister * temp);118119TR_OpaquePseudoRegister * allocateOpaquePseudoRegister(TR::DataType dt);120TR_OpaquePseudoRegister * allocateOpaquePseudoRegister(TR_OpaquePseudoRegister *reg);121TR_PseudoRegister * allocatePseudoRegister(TR::DataType dt);122TR_PseudoRegister * allocatePseudoRegister(TR_PseudoRegister *reg);123124TR_OpaquePseudoRegister * evaluateOPRNode(TR::Node* node);125TR_PseudoRegister * evaluateBCDNode(TR::Node * node);126127// --------------------------------------------------------------------------128// Storage references129//130bool getAddStorageReferenceHints() { return _cgFlags.testAny(S390CG_addStorageReferenceHints);}131void setAddStorageReferenceHints() { _cgFlags.set(S390CG_addStorageReferenceHints);}132133bool storageReferencesMatch(TR_StorageReference *ref1, TR_StorageReference *ref2);134void processUnusedStorageRef(TR_StorageReference *ref);135void freeUnusedTemporaryBasedHint(TR::Node *node);136137138139/**140* Will a BCD left shift always leave the sign code unchanged and thus141* allow it to be propagated through and upwards142*/143bool propagateSignThroughBCDLeftShift(TR::DataType type)144{145if (type.isAnyPacked())146return false; // may use SRP that will always generate a 0xC or 0xD147else148return true;149}150151bool isAcceptableDestructivePDModPrecision(TR::Node *storeNode, TR::Node *nodeForAliasing);152bool isAcceptableDestructivePDShiftRight(TR::Node *storeNode, TR::Node *nodeForAliasing);153154bool validateAddressOneToAddressOffset(int32_t expectedOffset, TR::Node *addr1, int64_t addr1ExtraOffset, TR::Node *addr2, int64_t addr2ExtraOffset, TR::list<TR::Node*> *_baseLoadsThatAreNotKilled, bool trace);155void getAddressOneToAddressTwoOffset(bool *canGetOffset, TR::Node *addr1, int64_t addr1ExtraOffset, TR::Node *addr2, int64_t addr2ExtraOffset, int32_t *offset, TR::list<TR::Node*> *_baseLoadsThatAreNotKilled, bool trace);156157template <class TR_AliasSetInterface>158bool canUseSingleStoreAsAnAccumulator(TR::Node *parent,159TR::Node *node,160TR::Node *store,161TR_AliasSetInterface &storeAliases,162TR::list<TR::Node*> *conflictingAddressNodes,163bool justLookForConflictingAddressNodes,164bool isChainOfFirstChildren,165bool mustCheckAllNodes);166167TR::Node *getAddressLoadVar(TR::Node *node, bool trace);168169void markStoreAsAnAccumulator(TR::Node *node);170void addStorageReferenceHints(TR::Node *node);171void examineNode(TR::Node *parent, TR::Node *node, TR::Node *&bestNode, int32_t &storeSize, TR::list<TR::Node*> &leftMostNodesList);172void processNodeList(TR::Node *&bestNode, int32_t &storeSize, TR::list<TR::Node*> &leftMostNodesList);173174void correctBadSign(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, TR::MemoryReference *memRef);175176int32_t genSignCodeSetting(TR::Node *node, TR_PseudoRegister *targetReg, int32_t endByte, TR::MemoryReference *signCodeMR, int32_t sign, TR_PseudoRegister *srcReg, int32_t digitsToClear, bool numericNibbleIsZero);177178void widenBCDValue(TR::Node *node, TR_PseudoRegister *reg, int32_t startByte, int32_t endByte, TR::MemoryReference *targetMR);179180void widenBCDValueIfNeeded(TR::Node *node, TR_PseudoRegister *reg, int32_t startByte, int32_t endByte, TR::MemoryReference *targetMR);181void genZeroLeftMostDigitsIfNeeded(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, int32_t digitsToClear, TR::MemoryReference *targetMR, bool widenOnLeft=false);182void clearByteRangeIfNeeded(TR::Node *node, TR_PseudoRegister *reg, TR::MemoryReference *targetMR, int32_t startByte, int32_t endByte, bool widenOnLeft=false);183void genZeroLeftMostPackedDigits(TR::Node *node, TR_PseudoRegister *reg, int32_t endByte, int32_t digitsToClear, TR::MemoryReference *targetMR, int32_t memRefOffset=0);184185void initializeStorageReference(TR::Node *node,186TR_OpaquePseudoRegister *destReg,187TR::MemoryReference *destMR,188int32_t destSize,189TR::Node *srcNode,190TR_OpaquePseudoRegister *srcReg,191TR::MemoryReference *sourceMR,192int32_t sourceSize,193bool performExplicitWidening,194bool alwaysLegalToCleanSign,195bool trackSignState);196197TR_StorageReference *initializeNewTemporaryStorageReference(TR::Node *node,198TR_OpaquePseudoRegister *destReg,199int32_t destSize,200TR::Node *srcNode,201TR_OpaquePseudoRegister *srcReg,202int32_t sourceSize,203TR::MemoryReference *sourceMR,204bool performExplicitWidening,205bool alwaysLegalToCleanSign,206bool trackSignState);207208TR_OpaquePseudoRegister *privatizePseudoRegister(TR::Node *node, TR_OpaquePseudoRegister *reg, TR_StorageReference *storageRef, size_t sizeOverride = 0);209TR_OpaquePseudoRegister *privatizePseudoRegisterIfNeeded(TR::Node *parent, TR::Node *child, TR_OpaquePseudoRegister *childReg);210211TR_StorageReference *privatizeStorageReference(TR::Node *node, TR_OpaquePseudoRegister *reg, TR::MemoryReference *sourceMR);212TR_PseudoRegister *privatizeBCDRegisterIfNeeded(TR::Node *parent, TR::Node *child, TR_OpaquePseudoRegister *childReg);213214TR::MemoryReference *materializeFullBCDValue(TR::Node *node, TR_PseudoRegister *®, int32_t resultSize, int32_t clearSize=0, bool updateStorageReference=false, bool alwaysEnforceSSLimits=true);215216bool useMoveImmediateCommon(TR::Node *node,217char *srcLiteral,218size_t srcSize,219TR::Node *srcNode,220size_t destSize,221intptr_t destBaseOffset,222size_t destLeftMostByte,223TR::MemoryReference *destMR);224225bool checkFieldAlignmentForAtomicLong();226227bool canCopyWithOneOrTwoInstrs(char *lit, size_t size);228bool inlineSmallLiteral(size_t srcSize, char *srcLiteral, size_t destSize, bool trace);229230#if defined(J9VM_JIT_FREE_SYSTEM_STACK_POINTER)231/** \brief232* Determines whether the JIT supports freeing up the system stack pointer (SSP) for register allocation.233*234* \return235* <c>true</c> if <c>J9VM_JIT_FREE_SYSTEM_STACK_POINTER</c> is defined; <c>false</c> otherwise.236*237* \note238* <c>J9VM_JIT_FREE_SYSTEM_STACK_POINTER</c> is currently only defined on z/OS. For exception handling,239* additional frames are typically allocated on the system stack. Hence, the OS needs to be able to locate240* the system stack at all times in case of interrupts. In case of z/OS, we have the mechanism to save the241* SSP in a memory location (off <c>J9VMThread</c>) that is registered with the OS. We don't have such242* support on Linux, and hence, this is z/OS specific at the moment.243*/244bool supportsJITFreeSystemStackPointer()245{246return true;247}248#endif249250bool suppressInliningOfRecognizedMethod(TR::RecognizedMethod method);251252bool inlineDirectCall(TR::Node *node, TR::Register *&resultReg);253254#ifdef J9VM_OPT_JAVA_CRYPTO_ACCELERATION255bool inlineCryptoMethod(TR::Node *node, TR::Register *&resultReg);256#endif257258void incRefCountForOpaquePseudoRegister(TR::Node * node);259260/** \brief261* Generates a VM call helper sequence along with the necessary metadata in the instruction stream which when262* executed reverts the execution of this JIT body back to the interpreter.263*264* \param cursor265* The cursor to which the generated instructions will be appended.266*267* \param vmCallHelperSnippetLabel268* The label which is used to call this snippet.269*270* \return271* The last generated instruction.272*/273TR::Instruction* generateVMCallHelperSnippet(TR::Instruction* cursor, TR::LabelSymbol* vmCallHelperSnippetLabel);274275/** \brief276* Generates a VM call helper preprologue using \see generateVMCallHelperSnippet and generates the necessary277* metadata as well as data constants needed for invoking the snippet.278*279* \param cursor280* The cursor to which the generated instructions will be appended.281*282* \return283* The last generated instruction.284*/285TR::Instruction* generateVMCallHelperPrePrologue(TR::Instruction* cursor);286287/**288* \brief289* The number of nodes between a monexit and the next monent before transforming290* a monitored region with transactional lock elision. On Z, 25-30 cycles are291* required between transactions or else the latter transaction will be aborted292* (with significant penalty).293*294* \return295* 45. This is an estimate based on CPI of 1.5-2 and an average of 1 instruction296* per node.297*/298int32_t getMinimumNumberOfNodesBetweenMonitorsForTLE() { return 45; }299300/** \brief301* Sets whether decimal overflow or fixed point overflow checks should be generated for instructions which302* support such by-passes.303*304* \note305* This is applicable to z15 hardware accelerated vector packed decimal operations and is typically used to306* control whether the ignore overflow mask (IOM) bit is set in vector packed decimal instructions.307*/308void setIgnoreDecimalOverflowException(bool v)309{310_ignoreDecimalOverflowException = v;311}312313/** \brief314* Gets whether decimal overflow or fixed point overflow checks should be generated for instructions which315* support such by-passes.316*317* \note318* This is applicable to z15 hardware accelerated vector packed decimal operations and is typically used to319* control whether the ignore overflow mask (IOM) bit is set in vector packed decimal instructions.320*/321bool getIgnoreDecimalOverflowException()322{323return _ignoreDecimalOverflowException;324}325326// LL: move to .cpp327bool arithmeticNeedsLiteralFromPool(TR::Node *node);328329/**330* \brief Determines whether the code generator supports stack allocations331*/332bool supportsStackAllocations() { return true; }333334// See J9::CodeGenerator::guaranteesResolvedDirectDispatchForSVM335bool guaranteesResolvedDirectDispatchForSVM() { return true; }336337private:338339/** \brief340* Determines whether decimal overflow or fixed point overflow checks should be generated for instructions which341* support such by-passes.342*/343bool _ignoreDecimalOverflowException;344};345346}347348}349350#endif351352353