| /********************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| **********************************************************************/ |
| |
| // Native Expressions only officially supported on Linux for now. |
| |
| /////////////////////////////////////////////////////////////////////// |
| // |
| // The following are a few notes regarding native exprs |
| // |
| // 1. A few things are implemented differently for native expressions. |
| // For example, NULL values will be represented internally as an unsigned |
| // char. It will have either a non-zero value (null) or zero value (not |
| // null). |
| // |
| // 2. Code the the pcode graph is generated in program layout order for |
| // libjit, as there doesn't seem to be any other way or doing this. This |
| // can prove difficult in maintaining correctness for determining the temps |
| // that correspond to various operands. |
| // |
| // 3. Related to (2), both getJitValue() and storeJitValue() may need to be |
| // re-examined (specifically for attempting to use a jitValue_ that was |
| // declared along one particular path, but not on another. Since jitValue_ |
| // for an operand is saved irrespective of control flow, we can have problems |
| // |
| // 4. If a value is created in along a conditional path, it may still be |
| // referenced anywhere if it is marked addressable. |
| // |
| /////////////////////////////////////////////////////////////////////// |
| |
| #include "Platform.h" |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| #include "NAAssert.h" |
| |
| // This #define must come *before* the #include "ExpPCodeOptimizations.h" line |
| #define COMING_FROM_NATIVE_EXPR_SOURCE_FILE |
| |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #include "ExpPCodeOptimizations.h" |
| #include <signal.h> |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| #include "llvm/Support/raw_ostream.h" /* FOR NEW MODULE DUMPING IDEA */ |
| #include "llvm/Support/InstIterator.h" /* FOR NEW MODULE DUMPING IDEA */ |
| #include <fstream> |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| // |
| // NExLog() - Routine used to log Native Expression debug info to the |
| // log file for this instance of the Compiler. |
| // |
| void PCodeCfg::NExLog(const char *data) |
| { |
| char * NExLogPth = NULL ; |
| |
| if ( NExDbgInfoPtr_ && NExDbgInfoPtr_ > (NExDbgInfo *)4096 ) // May be offset |
| NExLogPth = NExDbgInfoPtr_->getNExLogPath() ; |
| |
| if ( NExLogPth && // May be null when called by showplan |
| *NExLogPth != '\0' ) // OR may have null pathname |
| { |
| ofstream fileout( NExLogPth, ios::app); |
| fileout << data ; |
| } |
| } |
| |
| #if NExprDbgLvl > VV_NO |
| // |
| // For routines in the PCodeCfg class, we have access to the |
| // NExprDbgLvl_ member variable and we use it to determine how |
| // verbose the user wants the output to be. |
| // |
| #define DPT0( str1, VBlvl, str2 ) \ |
| { if ( NExprDbgLvl_ >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2 ); \ |
| NExLog( NExBuf ); } } |
| #define DPT1( str1, VBlvl, str2, Arg5 ) \ |
| { if ( NExprDbgLvl_ >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5 ); \ |
| NExLog( NExBuf ); } } |
| #define DPT2( str1, VBlvl, str2, Arg5, Arg6 ) \ |
| { if ( NExprDbgLvl_ >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6 ); \ |
| NExLog( NExBuf ); } } |
| #define DPT3( str1, VBlvl, str2, Arg5, Arg6, Arg7 ) \ |
| { if ( NExprDbgLvl_ >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7 ); \ |
| NExLog( NExBuf ); } } |
| #define DPT4( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8 ) \ |
| { if ( NExprDbgLvl_ >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7, Arg8 ); \ |
| NExLog( NExBuf ); } } |
| #define DPT5( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9 ) \ |
| { if ( NExprDbgLvl_ >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7, Arg8, Arg9 ); \ |
| NExLog( NExBuf ); } } |
| #define DPT6( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10 ) \ |
| { if ( NExprDbgLvl_ >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10 ); \ |
| NExLog( NExBuf ); } } |
| // |
| // NOTE: The following CDPTxx macros are useable ONLY within routines |
| // that have 'cfg' defined as a pointer to the PCodeCfg. |
| // |
| #define CDPT0( str1, VBlvl, str2 ) \ |
| { if ( cfg->getNExprDbgLvl() >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2 ); \ |
| cfg->NExLog( NExBuf ); } } |
| #define CDPT1( str1, VBlvl, str2, Arg5 ) \ |
| { if ( cfg->getNExprDbgLvl() >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5 ); \ |
| cfg->NExLog( NExBuf ); } } |
| #define CDPT2( str1, VBlvl, str2, Arg5, Arg6 ) \ |
| { if ( cfg->getNExprDbgLvl() >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6 ); \ |
| cfg->NExLog( NExBuf ); } } |
| #define CDPT3( str1, VBlvl, str2, Arg5, Arg6, Arg7 ) \ |
| { if ( cfg->getNExprDbgLvl() >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7 ); \ |
| cfg->NExLog( NExBuf ); } } |
| #define CDPT4( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8 ) \ |
| { if ( cfg->getNExprDbgLvl() >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7, Arg8 ); \ |
| cfg->NExLog( NExBuf ); } } |
| #define CDPT5( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9 ) \ |
| { if ( cfg->getNExprDbgLvl() >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7, Arg8, Arg9 ); \ |
| cfg->NExLog( NExBuf ); } } |
| #define CDPT6( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10 ) \ |
| { if ( cfg->getNExprDbgLvl() >= VBlvl ) { \ |
| sprintf( NExBuf, str1 str2, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10 ); \ |
| cfg->NExLog( NExBuf ); } } |
| |
| |
| #define PRINT_DETAILS_OF_RDOp( OpNum, PCOp ) { \ |
| if ( NExprDbgLvl_ >= VV_XD ) { \ |
| if ( PCOp->getStackIndex() == 2 ) \ |
| sprintf( NExBuf, "DETAILS of RD_Op[%d] at %p " \ |
| "WITH stackIndex_ = 2 are: \n", \ |
| OpNum, PCOp ); \ |
| else \ |
| sprintf( NExBuf, "DETAILS of RD_Op[%d] at %p are: \n", OpNum, PCOp );\ |
| NExLog( NExBuf ); \ |
| sprintf( NExBuf, "stackIndex_ = %d, offset_ = %d, len_=%d, " \ |
| "operandType_=%d, nullBitIdx=%d, CJV=%p\n", \ |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), \ |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal());\ |
| NExLog( NExBuf ); \ |
| } \ |
| } |
| |
| #define PRINT_DETAILS_OF_WROp( OpNum, PCOp ) { \ |
| if ( NExprDbgLvl_ >= VV_XD ) { \ |
| if ( PCOp->getStackIndex() == 2 ) \ |
| sprintf( NExBuf, "DETAILS of WR_Op[%d] at %p " \ |
| "WITH stackIndex_ = 2 are: \n", \ |
| OpNum, PCOp ); \ |
| else \ |
| sprintf( NExBuf, "DETAILS of WR_Op[%d] at %p are: \n", OpNum, PCOp );\ |
| NExLog( NExBuf ); \ |
| sprintf( NExBuf, "stackIndex_ = %d, offset_ = %d, len_=%d, " \ |
| "operandType_=%d, nullBitIdx=%d, CJV=%p\n", \ |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), \ |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal());\ |
| NExLog( NExBuf ); \ |
| } \ |
| } |
| #else /* Define this macros to result in nothing. */ |
| #define DPT0( str1, VBlvl, str2 ) |
| #define DPT1( str1, VBlvl, str2, Arg5 ) |
| #define DPT2( str1, VBlvl, str2, Arg5, Arg6 ) |
| #define DPT3( str1, VBlvl, str2, Arg5, Arg6, Arg7 ) |
| #define DPT4( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8 ) |
| #define DPT5( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9 ) |
| #define DPT6( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10 ) |
| #define CDPT0( str1, VBlvl, str2 ) |
| #define CDPT1( str1, VBlvl, str2, Arg5 ) |
| #define CDPT2( str1, VBlvl, str2, Arg5, Arg6 ) |
| #define CDPT3( str1, VBlvl, str2, Arg5, Arg6, Arg7 ) |
| #define CDPT4( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8 ) |
| #define CDPT5( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9 ) |
| #define CDPT6( str1, VBlvl, str2, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10 ) |
| #define PRINT_DETAILS_OF_RDOp( OpNum, PCOp ) |
| #define PRINT_DETAILS_OF_WROp( OpNum, PCOp ) |
| |
| #endif /* NExprDbgLvl >= VV_I0 */ |
| |
| #include "exp_datetime.h" |
| |
| |
| #include "udis86.h" |
| |
| #include <sstream> |
| #include <iostream> |
| using namespace llvm; |
| |
| |
| |
| // Can we have null tuple pointers (no, if we're on R2.5) |
| #define NULL_TUPLE_PTRS 0 |
| |
| // |
| // Compute the dominator tree |
| // |
| void PCodeCfg::computeDomTree() |
| { |
| CollIndex i; |
| |
| // First we clear bit vector that tracks available ops. |
| // |
| // NOTE: We are using the onesVector to hold the "Dominator Tree" info. |
| // There is a onesVector for each PCBlock. For any particular PCBlock X, |
| // if the bit corresponding to PCBlock Y is ON (in block X's onesVector), |
| // then it means that PCBlock Y "dominates" block X. That is, *all* paths |
| // in the flow graph (PCodeCfg) from the entry block to block X are |
| // guaranteed to go through block Y. |
| // |
| FOREACH_BLOCK_REV_DFO( PCBlk, firstPCInst, lastPCInst, indx ) { |
| PCBlk->onesVector.clear(); |
| } ENDFE_BLOCK_REV_DFO |
| |
| FOREACH_BLOCK_REV_DFO( PCBlk, firstPCInst, lastPCInst, indx ) { |
| |
| // IN = INTERSECT(PREDS) |
| for (i=0; i < PCBlk->getPreds().entries(); i++) { |
| if (i == 0) |
| PCBlk->onesVector = PCBlk->getPreds()[i]->onesVector; |
| else |
| PCBlk->onesVector.intersectSet(PCBlk->getPreds()[i]->onesVector); |
| } |
| |
| // Every PCode block dominates itself (immediate dominator) |
| PCBlk->onesVector += PCBlk->getBlockNum(); |
| |
| } ENDFE_BLOCK_REV_DFO |
| } |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| // |
| // NatExprName: routine used by debug and instrumentation code to |
| // return a PCode Instruction name given its opcode. |
| // |
| // NOTE: This routine handles only the opcodes for PCODE instructions |
| // that are translatable to native code. |
| // |
| // NOTE: In the future, as more PCODE instructions are made translatable |
| // to native code, the routine should have lines of code added |
| // to know about the new PCODE instructions. |
| // |
| #if NExprDbgLvl > VV_NO |
| const char * NatExprName( Int32 opc ) |
| { |
| switch ( opc ) |
| { |
| case PCIT::OPDATA_MPTR32_IBIN32S: {return "OPDATA_MPTR32_IBIN32S" ; break;} |
| case PCIT::OPDATA_MBIN16U_IBIN32S: {return "OPDATA_MBIN16U_IBIN32S"; break;} |
| case PCIT::MOVE_MBIN32S: {return "MOVE_MBIN32S" ; break;} |
| case PCIT::MOVE_MBIN32S_IBIN32S: {return "MOVE_MBIN32S_IBIN32S"; break;} |
| case PCIT::MOVE_MBIN8_MBIN8_IBIN32S: {return "MOVE_MBIN8_MBIN8_IBIN32S"; break;} |
| case PCIT::MOVE_MBIN32U_MBIN16U: {return "MOVE_MBIN32U_MBIN16U"; break;} |
| case PCIT::MOVE_MBIN32S_MBIN16U: {return "MOVE_MBIN32S_MBIN16U"; break;} |
| case PCIT::MOVE_MBIN64S_MBIN16U: {return "MOVE_MBIN64S_MBIN16U"; break;} |
| case PCIT::MOVE_MBIN32U_MBIN16S: {return "MOVE_MBIN32U_MBIN16S"; break;} |
| case PCIT::MOVE_MBIN32S_MBIN16S: {return "MOVE_MBIN32S_MBIN16S"; break;} |
| case PCIT::MOVE_MBIN64S_MBIN16S: {return "MOVE_MBIN64S_MBIN16S"; break;} |
| case PCIT::MOVE_MBIN64S_MBIN32U: {return "MOVE_MBIN64S_MBIN32U"; break;} |
| case PCIT::MOVE_MBIN64S_MBIN32S: {return "MOVE_MBIN64S_MBIN32S"; break;} |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S: {return "EQ_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32S: {return "EQ_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S: {return "EQ_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U: {return "EQ_MBIN32S_MBIN16U_MBIN16U"; break;} |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN32U: {return "EQ_MBIN32S_MBIN16U_MBIN32U"; break;} |
| case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U: {return "EQ_MBIN32S_MBIN32U_MBIN32U"; break;} |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32U: {return "EQ_MBIN32S_MBIN16S_MBIN32U"; break;} |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN16S: {return "LT_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32S: {return "LT_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::LT_MBIN32S_MBIN32S_MBIN32S: {return "LT_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16U: {return "LT_MBIN32S_MBIN16U_MBIN16U"; break;} |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN32U: {return "LT_MBIN32S_MBIN16U_MBIN32U"; break;} |
| case PCIT::LT_MBIN32S_MBIN32U_MBIN32U: {return "LT_MBIN32S_MBIN32U_MBIN32U"; break;} |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN16S: {return "GT_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32S: {return "GT_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::GT_MBIN32S_MBIN32S_MBIN32S: {return "GT_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16U: {return "GT_MBIN32S_MBIN16U_MBIN16U"; break;} |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN32U: {return "GT_MBIN32S_MBIN16U_MBIN32U"; break;} |
| case PCIT::GT_MBIN32S_MBIN32U_MBIN32U: {return "GT_MBIN32S_MBIN32U_MBIN32U"; break;} |
| case PCIT::SUM_MBIN32S_MBIN32S: {return "SUM_MBIN32S_MBIN32S"; break;} |
| case PCIT::SUM_MBIN64S_MBIN64S: {return "SUM_MBIN64S_MBIN64S"; break;} |
| case PCIT::MINMAX_MBIN8_MBIN8_MBIN32S_IBIN32S: |
| {return "MINMAX_MBIN8_MBIN8_MBIN32S_IBIN32S"; break;} |
| case PCIT::BRANCH: {return "BRANCH"; break;} |
| case PCIT::CLAUSE_EVAL: {return "CLAUSE_EVAL"; break;} |
| case PCIT::FILL_MEM_BYTES: {return "FILL_MEM_BYTES"; break;} |
| case PCIT::MOVE_MBIN16U_IBIN16U: {return "MOVE_MBIN16U_IBIN16U"; break;} |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN16S: {return "LE_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32S: {return "LE_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::LE_MBIN32S_MBIN32S_MBIN32S: {return "LE_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16U: {return "LE_MBIN32S_MBIN16U_MBIN16U"; break;} |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN32U: {return "LE_MBIN32S_MBIN16U_MBIN32U"; break;} |
| case PCIT::LE_MBIN32S_MBIN32U_MBIN32U: {return "LE_MBIN32S_MBIN32U_MBIN32U"; break;} |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN16S: {return "GE_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32S: {return "GE_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::GE_MBIN32S_MBIN32S_MBIN32S: {return "GE_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16U: {return "GE_MBIN32S_MBIN16U_MBIN16U"; break;} |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN32U: {return "GE_MBIN32S_MBIN16U_MBIN32U"; break;} |
| case PCIT::GE_MBIN32S_MBIN32U_MBIN32U: {return "GE_MBIN32S_MBIN32U_MBIN32U"; break;} |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S: {return "EQ_MBIN32S_MBIN16U_MBIN16S"; break;} |
| case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S: {return "EQ_MBIN32S_MBIN64S_MBIN64S"; break;} |
| case PCIT::LT_MBIN32S_MBIN64S_MBIN64S: {return "LT_MBIN32S_MBIN64S_MBIN64S"; break;} |
| case PCIT::LE_MBIN32S_MBIN64S_MBIN64S: {return "LE_MBIN32S_MBIN64S_MBIN64S"; break;} |
| case PCIT::GT_MBIN32S_MBIN64S_MBIN64S: {return "GT_MBIN32S_MBIN64S_MBIN64S"; break;} |
| case PCIT::GE_MBIN32S_MBIN64S_MBIN64S: {return "GE_MBIN32S_MBIN64S_MBIN64S"; break;} |
| case PCIT::BRANCH_AND: {return "BRANCH_AND"; break;} |
| case PCIT::BRANCH_OR: {return "BRANCH_OR"; break;} |
| case PCIT::MOVE_MBIN8_MBIN8: {return "MOVE_MBIN8_MBIN8"; break;} |
| case PCIT::MOVE_MBIN16U_MBIN16U: {return "MOVE_MBIN16U_MBIN16U"; break;} |
| case PCIT::MOVE_MBIN32U_MBIN32U: {return "MOVE_MBIN32U_MBIN32U"; break;} |
| case PCIT::MOVE_MBIN64S_MBIN64S: {return "MOVE_MBIN64S_MBIN64S"; break;} |
| case PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S: {return "OPDATA_MPTR32_IBIN32S_IBIN32S"; break;} |
| case PCIT::OPDATA_MATTR5_IBIN32S: {return "OPDATA_MATTR5_IBIN32S"; break;} |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| {return "NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S"; break;} |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| {return "NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S"; break;} |
| case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S: |
| {return "NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S"; break;} |
| case PCIT::RETURN: {return "RETURN"; break;} |
| case PCIT::RETURN_IBIN32S: {return "RETURN_IBIN32S"; break;} |
| case PCIT::MOVE_MATTR5_MATTR5: {return "MOVE_MATTR5_MATTR5"; break;} |
| case PCIT::MOVE_MBIN16U_MBIN8: {return "MOVE_MBIN16U_MBIN8"; break;} |
| case PCIT::NNB_MATTR3_IBIN32S: {return "NNB_MATTR3_IBIN32S"; break;} |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| {return "NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S"; break;} |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| {return "NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S"; break;} |
| case PCIT::NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S: |
| {return "NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S"; break;} |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN32S_MBIN32S: |
| {return "SUM_MATTR3_MATTR3_IBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S: |
| {return "SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S"; break;} |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S: |
| {return "SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S"; break;} |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN16S: {return "ADD_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::ADD_MBIN16S_MBIN16S_MBIN16S: {return "ADD_MBIN16S_MBIN16S_MBIN16S"; break;} |
| case PCIT::ADD_MBIN32S_MBIN32S_MBIN32S: {return "ADD_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S: {return "ADD_MBIN64S_MBIN64S_MBIN64S"; break;} |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN32S: {return "ADD_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S: {return "ADD_MBIN64S_MBIN32S_MBIN64S"; break;} |
| case PCIT::SUB_MBIN16S_MBIN16S_MBIN16S: {return "SUB_MBIN16S_MBIN16S_MBIN16S"; break;} |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN32S: {return "SUB_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S: {return "SUB_MBIN64S_MBIN64S_MBIN64S"; break;} |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN16S: {return "SUB_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN32S: {return "SUB_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN16S: {return "SUB_MBIN32S_MBIN32S_MBIN16S"; break;} |
| case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S: {return "MUL_MBIN32S_MBIN32S_MBIN32S"; break;} |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S: {return "MUL_MBIN32S_MBIN16S_MBIN16S"; break;} |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S: {return "MUL_MBIN32S_MBIN16S_MBIN32S"; break;} |
| case PCIT::MUL_MBIN16S_MBIN16S_MBIN16S: {return "MUL_MBIN16S_MBIN16S_MBIN16S"; break;} |
| case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S: {return "MUL_MBIN64S_MBIN64S_MBIN64S"; break;} |
| case PCIT::MUL_MBIN64S_MBIN16S_MBIN32S: {return "MUL_MBIN64S_MBIN16S_MBIN32S"; break;} |
| case PCIT::MUL_MBIN64S_MBIN32S_MBIN32S: {return "MUL_MBIN64S_MBIN32S_MBIN32S"; break;} |
| case PCIT::FILL_MEM_BYTES_VARIABLE: {return "FILL_MEM_BYTES_VARIABLE" ; break;} |
| case PCIT::EQ_MBIN32S_MASCII_MASCII: {return "EQ_MBIN32S_MASCII_MASCII" ; break;} |
| case PCIT::NE_MBIN32S_MASCII_MASCII: {return "NE_MBIN32S_MASCII_MASCII" ; break;} |
| case PCIT::LT_MBIN32S_MASCII_MASCII: {return "LT_MBIN32S_MASCII_MASCII" ; break;} |
| case PCIT::GT_MBIN32S_MASCII_MASCII: {return "GT_MBIN32S_MASCII_MASCII" ; break;} |
| case PCIT::LE_MBIN32S_MASCII_MASCII: {return "LE_MBIN32S_MASCII_MASCII" ; break;} |
| case PCIT::GE_MBIN32S_MASCII_MASCII: {return "GE_MBIN32S_MASCII_MASCII" ; break;} |
| default: |
| return "Opcode UNSUPPORTED by NatExprName()" ; |
| } |
| } |
| #endif /* #if NExprDbgLvl >= VV_I1 */ |
| |
| // |
| // inTempsList() - Routine used to determine if the specified Temp operand |
| // is already in the Temps List. |
| // |
| NABoolean PCodeCfg::inTempsList( Int32 Offset, PCIT::AddressingMode OprTyp ) |
| { |
| for ( Int32 tli = 0 ; tli < NExTempsList_->entries() ; tli++ ) |
| { |
| NExTempListEntry * tliEntry = (*NExTempsList_)[tli] ; |
| |
| if ( ( Offset == tliEntry->getOffset() ) && ( OprTyp == tliEntry->getOprTyp() ) ) |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| // |
| // addToTempsList() - Routine used to add the specified Temp operand |
| // to the Temps List. |
| // |
| void PCodeCfg::addToTempsList( PCodeOperand * PCOp |
| , PCIT::AddressingMode OprTyp |
| , Int32 Offset |
| , Int32 Num |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| DPT4( "VVA2T0: ", VV_XD, "In addToTempsList( %p, OprTyp = %d, Offset=%d, Num=%d)\n", |
| PCOp, (Int32) OprTyp, Offset, Num ) ; |
| CollIndex i = PCOp->getBvIndex(); |
| PCodeOperand* operand = this->getMap()->getFirstValue(&i); |
| |
| #if NExprDbgLvl >= VV_BD |
| PRINT_DETAILS_OF_WROp( 0, PCOp ); |
| DPT2( "VVA2T3: ", VV_XD, "In addToTempsList(): operand=%p, PCOp=%p\n", |
| operand, PCOp ); |
| |
| if (operand != NULL && operand != PCOp ) |
| PRINT_DETAILS_OF_WROp( 0, operand ); |
| #endif |
| |
| if (operand != NULL && operand != PCOp ) |
| { |
| PCOp = operand; |
| OprTyp = operand->getType(); |
| // We assume that operand's offset and num values are the same as PCOp's values. |
| } |
| |
| if ( inTempsList( Offset, OprTyp ) ) |
| return; // We will resuse the existing allocated space |
| |
| DPT1( "VVA2T4: ", VV_XD, "At start, NExTempsList_->entries() = %d\n", NExTempsList_->entries() ); |
| |
| NExTempListEntry * newEntry = new(heap_) NExTempListEntry(); |
| |
| newEntry->setPCOp( PCOp ) ; |
| newEntry->setOprTyp( OprTyp ) ; |
| newEntry->setOffset( Offset ) ; |
| newEntry->setNum( Num ) ; |
| |
| DPT0( "VVA2T9: ", VV_XD, "Inserting into TempsList\n"); |
| NExTempsList_->insert( newEntry ); |
| } |
| |
| // |
| // Return TRUE if native instructions can be generated for this pcode graph. |
| // |
| NABoolean PCodeCfg::canGenerateNativeExpr() |
| { |
| #if NExprDbgLvl >= VV_NO |
| char NExBuf[500]; |
| #endif |
| |
| #if NExprDbgLvl >= VV_I2 |
| NABoolean RTNV = TRUE ; // Return TRUE for now. |
| Int32 NumBad = 0 ; |
| Int32 BadOpc = 0 ; |
| #endif |
| |
| FOREACH_BLOCK_REV_DFO(PCBlk, firstPCInst, lastPCInst, indx) { |
| FOREACH_INST_IN_BLOCK(PCBlk, PCInst) { |
| |
| //DPT1( "VVYN00: ", VV_I3, "In canGEN loop: Found opcd = %d \n", (int) PCInst->getOpcode() ); |
| Int32 opc = PCInst->getOpcode() ; |
| switch ( opc ) |
| { |
| |
| // PCode Instructions with 0 Read Operands AND 0 Write Operands |
| |
| case PCIT::BRANCH: |
| case PCIT::RETURN: |
| case PCIT::RETURN_IBIN32S: |
| { |
| DPT2( "VVY001: ", VV_I3, "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| } |
| |
| |
| // PCode Instructions with 1 Read Operand AND 0 Write Operands |
| |
| case PCIT::NNB_MATTR3_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| { |
| PCodeOperand* read = PCInst->getROps()[0]; |
| if ( read->isTemp() && ! inTempsList( read->getOffset(), read->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| //Otherwise, instruction is OK |
| |
| DPT2("VVY001: ", VV_I3, "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| } |
| case PCIT::OPDATA_MPTR32_IBIN32S: |
| case PCIT::OPDATA_MBIN16U_IBIN32S: |
| case PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S: |
| case PCIT::OPDATA_MATTR5_IBIN32S: |
| { |
| if ( PCInst->getWOps().entries() ) |
| { |
| NABoolean canHandle = TRUE; |
| OPLIST opList = PCInst->getWOps() ; |
| for (Int32 iii = 0; iii < opList.entries(); iii++ ) |
| { |
| PCodeOperand *PCOp = opList[iii]; |
| if ( PCOp->getStackIndex() == 2 ) // DON'T YET KNOW HOW TO HANDLE THIS with LLVM! |
| { |
| canHandle = FALSE ; |
| |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN001: ", VV_I3, "Cannot GENERATE for PCODE " |
| "opcode %3d - Writes To Temp Var\n", |
| PCInst->getOpcode() ); |
| DPT6( "VVN001a: ", VV_I3, "Details of Bad Temp Var:\n" |
| "stackIndex_ = %d, offset_ = %d, len_=%d, " |
| "operandType_=%d, nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), |
| PCOp->getLen(), PCOp->getType(), |
| PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| if ( canHandle == FALSE ) |
| break; |
| } |
| else // May have Read Operands |
| { |
| OPLIST opList = PCInst->getROps() ; |
| for (Int32 iii = 0; iii < opList.entries(); iii++ ) |
| { |
| PCodeOperand *PCOp = opList[iii]; |
| if ( PCOp->isTemp() && ! inTempsList( PCOp->getOffset(), PCOp->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE " |
| "opcode %3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| } |
| |
| DPT2("VVY001: ", VV_I3, "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| } |
| |
| |
| // PCode Instructions with 2 Read Operands AND 1 Write Operand |
| |
| case PCIT::NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| case PCIT::EQ_MBIN32S_MASCII_MASCII: |
| case PCIT::NE_MBIN32S_MASCII_MASCII: |
| case PCIT::LT_MBIN32S_MASCII_MASCII: |
| case PCIT::GT_MBIN32S_MASCII_MASCII: |
| case PCIT::LE_MBIN32S_MASCII_MASCII: |
| case PCIT::GE_MBIN32S_MASCII_MASCII: |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S: |
| case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::MINMAX_MBIN8_MBIN8_MBIN32S_IBIN32S: |
| case PCIT::SUM_MBIN32S_MBIN32S: // (Note: not used by regression tests! ?) |
| case PCIT::SUM_MBIN64S_MBIN64S: |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN32S_MBIN32S_MBIN32S: |
| /////// case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S: // Cannot support yet: no overflow support |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN32S: |
| /////// case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S: // Cannot support yet: no overflow support |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::SUB_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN32S: |
| /////// case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S: // Cannot support yet: no overflow support |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN16S: |
| /////// case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S: // Cannot support yet: no overflow support |
| /////// case PCIT::MUL_MBIN64S_MBIN32S_MBIN32S: // Cannot support yet: no overflow support |
| /////// case PCIT::MUL_MBIN64S_MBIN16S_MBIN32S: // Cannot support yet: no overflow support |
| case PCIT::MUL_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S: |
| { |
| PCodeOperand* read = PCInst->getROps()[1]; |
| if ( read->isTemp() && ! inTempsList( read->getOffset(), read->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| /* FALLTHROUGH */ |
| |
| |
| // PCode Instructions with 1 Read Operand AND 1 Write Operand |
| |
| case PCIT::BRANCH_OR: |
| case PCIT::BRANCH_AND: |
| case PCIT::MOVE_MBIN16U_MBIN8: |
| case PCIT::MOVE_MBIN32U_MBIN16U: |
| case PCIT::MOVE_MBIN32S_MBIN16U: |
| case PCIT::MOVE_MBIN64S_MBIN16U: |
| case PCIT::MOVE_MBIN64S_MBIN32U: |
| case PCIT::MOVE_MBIN32U_MBIN16S: |
| case PCIT::MOVE_MBIN32S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN32S: |
| case PCIT::MOVE_MBIN16U_MBIN16U: |
| case PCIT::MOVE_MBIN8_MBIN8_IBIN32S: |
| case PCIT::MOVE_MBIN32U_MBIN32U: |
| case PCIT::MOVE_MBIN64S_MBIN64S: |
| { |
| // |
| // NOTE: PCIT::MOVE_MBIN16U_MBIN8, in particular, has been observed |
| // being used to reference the last part of a string that was put |
| // into Temp space (i.e. stackIndex_ == 2) by a preceding PCODE |
| // instruction. When this happens, PCodeOperand::getJitValue() |
| // comes to the conclusion that the reference to the last part of |
| // the string is a reference to a new (and hence *undefined*) |
| // temporary variable and does an assert(FALSE) since such a |
| // reference is not supposed to happen. Perhaps someday we will |
| // be able to figure out how to get getJitValue() to understand |
| // that the reference is OK, but for now, we just ensure this does |
| // not happen by preventing reads of Temp variables that appear to |
| // be undefined. Since we don't really know all the possible |
| // situations that could lead to apparently undefined temp variables, |
| // we test *all* reads of Temp variables by *any* PCODE instructions |
| // that take a Read Operand and, if it looks like it is an |
| // undefined Temp variable, we prevent generating a Native Expr. |
| // |
| PCodeOperand* read = PCInst->getROps()[0]; |
| if ( read->isTemp() && ! inTempsList( read->getOffset(), read->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| /* FALLTHROUGH */ |
| |
| |
| // PCode Instructions with 1 Write Operand |
| |
| case PCIT::MOVE_MBIN16U_IBIN16U: |
| case PCIT::MOVE_MBIN32S_IBIN32S: |
| { |
| PCodeOperand* write = PCInst->getWOps()[0]; |
| if ( write->isTemp() ) |
| { |
| // Some regression tests fail if these opcodes write to Temp variables! |
| // Perhaps someday this restriction will be removed? |
| if ( opc == PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN001: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Writes To Temp Var\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| addToTempsList( write , write->getType() , write->getOffset() ); |
| } |
| DPT2("VVY001: ", VV_I3, "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN8_MBIN8: |
| { |
| PCodeOperand * src1 = PCInst->getROps()[0]; |
| if ( src1->isTemp() && ! inTempsList( src1->getOffset(), src1->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| if ( src1->isConst() ) |
| { |
| if ( src1->getType() == PCIT::MPTR32 ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT0( "VVN002: ", VV_I3, "Cannot GENERATE for PCODE " |
| "opcode 200 - Const MPTR32 type\n"); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| } |
| #endif |
| return FALSE; |
| } |
| else |
| { |
| DPT3("VVY003: ", VV_I3, "CAN GENERATE for PCODE opcode " |
| "%3d %s type=%d\n", |
| opc, NatExprName( opc ), |
| (int)src1->getType() ); |
| PCodeOperand* write = PCInst->getWOps()[0]; |
| if ( write->isTemp() ) addToTempsList( write |
| , write->getType() |
| , write->getOffset() |
| ); |
| } |
| } |
| break; |
| } |
| |
| case PCIT::CLAUSE_EVAL: |
| { |
| // on 64-bit the clause pointer is in code[1] and code[2] |
| ex_clause* clause = (ex_clause*)*(Long*)&(PCInst->code[1]); |
| NABoolean processNulls = PCInst->code[1 + PCODEBINARIES_PER_PTR]; |
| |
| // Only certain clause eval instructions will be supported for now. |
| switch (clause->getClassID()) { |
| case ex_clause::AGGR_MIN_MAX_ID: |
| { |
| /* ZZZZ CAN WE LIFT THIS RESTRICTION ??? */ |
| // Because of the "assert(!opDataNulls[0]->forAlignedFormat());" |
| // line in the CLAUSE_EVAL handling within layoutNativeCode(), |
| // AND because that assertion is apparently no longer valid |
| // (as of 07/01/2013), we disallow the ex_clause::AGGR_MIN_MAX_ID |
| // clause for now -- until we can add code in the CLAUSE_EVAL |
| // handling to deal with AlignedFormat in the null indicator |
| // for the aggregate. |
| |
| #if 1 /* ZZZZ CAN WE LIFT THIS RESTRICTION ??? */ |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN005: ", VV_I3, "Cannot GENERATE for PCODE opcode %d -" |
| " AGGR_MIN_MAX_ID disallowed for now\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| |
| #else /* the old code: allow AGGR_MIN_MAX_ID when we know how to do so: */ |
| |
| // This clause must not call process nulls when evaluated |
| if (!processNulls) { |
| // Can only tolerate certain types for now. |
| if (isSupportedClauseOperandType(clause->getOperand(0))) |
| { |
| DPT2( "VVY004: ", VV_I3, |
| "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| } |
| |
| } |
| |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN005: ", VV_I3, "Cannot GENERATE for PCODE opcode %d -" |
| " AGGR processes nulls\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| #endif /* 1 */ |
| } |
| |
| case ex_clause::COMP_TYPE: |
| { |
| // No special nulls allowed for now. |
| if (clause->isSpecialNulls()) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN006: ", VV_I3, "Cannot GENERATE for PCODE opcode %d -" |
| " COMP_TYPE wants Special Nulls\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| switch (((ex_comp_clause*)clause)->getInstruction()) { |
| case NE_DATETIME_DATETIME: |
| case EQ_DATETIME_DATETIME: |
| case LT_DATETIME_DATETIME: |
| case GT_DATETIME_DATETIME: |
| case LE_DATETIME_DATETIME: |
| case GE_DATETIME_DATETIME: |
| { |
| // Only support standard types |
| long dtCode = |
| ((ExpDatetime*)(clause->getOperand(1)))->getPrecision(); |
| |
| // The lengths of the source operands must be the same. |
| if ((clause->getOperand(1)->getLength()) != |
| (clause->getOperand(1)->getLength())) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN007: ", VV_I3, "Cannot GENERATE for PCODE " |
| "opcode %d - COMP_TYPE Opers diff lengths\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| switch (dtCode) |
| { |
| case REC_DTCODE_DATE: |
| case REC_DTCODE_TIME: |
| case REC_DTCODE_TIMESTAMP: |
| DPT2( "VVY008: ", VV_I3, |
| "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| default: |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN009: ", VV_I3, "Cannot GENERATE for PCODE " |
| "opcode %d - COMP_TYPE unsupported dtCode\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| break; |
| } |
| |
| default: |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN010: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - COMP_TYPE unsupported D/T clause\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| break; |
| } |
| |
| default: |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN011: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - COMP_TYPE unsupported ClassID\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| break; |
| } |
| |
| case PCIT::FILL_MEM_BYTES: |
| { |
| PCodeOperand * write = PCInst->getWOps()[0]; |
| if ( write->isTemp() ) addToTempsList( write |
| , write->getType() |
| , write->getOffset() |
| , PCInst->code[3] |
| ); |
| break; |
| } |
| |
| case PCIT::FILL_MEM_BYTES_VARIABLE: |
| { |
| PCodeOperand* write = PCInst->getWOps()[0]; |
| |
| // Only support non-aligned format case. Otherwise we have to start |
| // tracking local varOffset (which we can do, but just not there yet). |
| if ( write->getVoaOffset() == -1 ) |
| { |
| DPT2("VVY012: ", VV_I3,"CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| |
| if ( write->isTemp() ) addToTempsList( write |
| , write->getType() |
| , write->getOffset() |
| , PCInst->code[6] |
| ); |
| break; |
| } |
| |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN013: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - getVoaOffset() != -1\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| case PCIT::MOVE_MATTR5_MATTR5: |
| { |
| PCodeOperand* read = PCInst->getROps()[0]; |
| PCodeOperand* write = PCInst->getWOps()[0]; |
| |
| if ( read->isTemp() && ! inTempsList( read->getOffset(), read->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| // Since we plan on copying everyting (length + string) in one shot, |
| // make sure the vc lengths of the operands are the same. |
| if (read->getVcIndicatorLen() != write->getVcIndicatorLen()) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN014: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - diff VcIndLen's\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| // For now, no support for temp varchars (since temp varchars will |
| // likely need to come from a separate temps area. |
| if (write->isTemp() || read->isTemp()) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN015: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - write->isTemp() || read->isTemp()\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| // Also, target max length must be greater than that of source |
| if (read->getVcMaxLen() > write->getVcMaxLen()) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN016: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - srcLen > tgtLen\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| DPT2( "VVY017: ", VV_I3, "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| } |
| |
| case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S: |
| { |
| PCodeOperand* write = PCInst->getWOps()[0]; |
| |
| // FIX: For now, just disallow the expr if write operand is not a temp |
| if ( ! write->isTemp() ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN022: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Writes to non temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| // Just don't support case with nullable varchar in packed format, |
| // since that requires an extra level of indirection when accessing |
| // the null indicator -- not expensive/complicated to implement, but |
| // rare enough to want to avoid. |
| |
| PCodeOperand* src = PCInst->getROps()[0]; |
| |
| if ( src->isTemp() && ! inTempsList( src->getOffset(), src->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| if ((src->getOffset() == -1) && !src->forAlignedFormat()) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN017: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - srcLen > tgtLen\n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| // Note: Could skip the write->isTemp() check in the next line |
| // since we assert'd that above, but that assert may be removed |
| // some day, so leave it for now...even though it is redundant. |
| if ( write->isTemp() ) addToTempsList( write |
| , write->getType() |
| , write->getOffset() |
| ); |
| DPT2( "VVY018: ", VV_I3, |
| "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| break; |
| } |
| |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN32S_MBIN32S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S: |
| { |
| // Make sure that this is nullable before we proceed |
| if (!PCInst->code[7]) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1( "VVN018: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - !PCInst->code[7] \n", |
| PCInst->getOpcode() ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| PCodeOperand * src1 = PCInst->getROps()[0]; |
| PCodeOperand * src2 = PCInst->getROps()[1]; |
| PCodeOperand * src3 = PCInst->getROps()[(PCInst->getROps()).entries()-1]; |
| |
| if ( ( src1->isTemp() && ! inTempsList( src1->getOffset(), src1->getType() ) ) || |
| ( src2->isTemp() && ! inTempsList( src2->getOffset(), src2->getType() ) ) || |
| ( src3->isTemp() && ! inTempsList( src3->getOffset(), src3->getType() ) ) |
| ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| |
| DPT2( "VVY019: ", VV_I3, |
| "CAN GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| |
| PCodeOperand * write = PCInst->getWOps()[ (PCInst->getWOps()).entries()-1 ]; |
| if ( write->isTemp() ) addToTempsList( write |
| , write->getType() |
| , write->getOffset() |
| ); |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN32S: |
| { |
| PCodeOperand* read = PCInst->getROps()[0]; |
| if ( read->isTemp() && ! inTempsList( read->getOffset(), read->getType() ) ) |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN030: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%3d %s - Reads undefined temp\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| // Only supported if RETURN follows it (as it always should) |
| if (PCInst->next && (PCInst->next->code[0] == PCIT::RETURN)) |
| { |
| DPT2( "VVY020: ", VV_I3, "CAN GENERATE for PCODE opcode " |
| "%3d %s\n", opc, NatExprName( opc ) ); |
| break; |
| } |
| |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT1("VVN021: ", VV_I3, "Cannot GENERATE for PCODE opcode " |
| "%d - not followed by RETURN\n", |
| PCInst->getOpcode()); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| default: |
| { |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT2( "VVN090: ", VV_I3,"Cannot GENERATE for PCODE opcode %3d %s\n", |
| opc, NatExprName( opc ) ); |
| RTNV = FALSE; |
| NumBad ++ ; BadOpc = opc; |
| break; |
| } |
| #endif |
| return FALSE; |
| } |
| } |
| } ENDFE_INST_IN_BLOCK |
| } ENDFE_BLOCK_REV_DFO |
| |
| #if NExprDbgLvl >= VV_I2 |
| if ( NumBad == 1 ) |
| { |
| DPT2( "VVN099: ", VV_I2, |
| "Cannot GENERATE for PCODE opcode %3d %s ONLY\n\n", |
| BadOpc, NatExprName( BadOpc ) ); |
| } |
| return RTNV; |
| #else |
| return TRUE; |
| #endif |
| } |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| // |
| // Return TRUE if native instructions can be generated for this pcode graph. |
| // |
| NABoolean PCodeCfg::canGenerateNativeExpr() |
| { |
| // . No persistent data (for now) |
| // . Only certain instructions |
| |
| FOREACH_BLOCK_REV_DFO(PCBlk, firstPCInst, lastPCInst, indx) { |
| FOREACH_INST_IN_BLOCK(PCBlk, inst) { |
| switch (inst->getOpcode()) { |
| case PCIT::BRANCH: |
| case PCIT::BRANCH_OR: |
| case PCIT::BRANCH_AND: |
| case PCIT::BRANCH_OR_CNT: |
| case PCIT::BRANCH_AND_CNT: |
| break; |
| |
| case PCIT::OR_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::AND_MBIN32S_MBIN32S_MBIN32S: |
| break; |
| |
| case PCIT::NNB_MATTR3_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| case PCIT::NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S: |
| break; |
| |
| case PCIT::FILL_MEM_BYTES: |
| break; |
| |
| case PCIT::FILL_MEM_BYTES_VARIABLE: |
| { |
| // Only support non-aligned format case. Otherwise we have to start |
| // tracking local varOffset (which we can do, but just not there yet). |
| if (inst->getWOps()[0]->getVoaOffset() == -1) |
| break; |
| |
| return FALSE; |
| } |
| |
| /* 64-bit comps (except EQ/NE) not supported in libjit. */ |
| //case PCIT::LT_MBIN32S_MBIN64S_MBIN64S: |
| //case PCIT::LE_MBIN32S_MBIN64S_MBIN64S: |
| //case PCIT::GT_MBIN32S_MBIN64S_MBIN64S: |
| //case PCIT::GE_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::NE_MBIN32S_MBIN64S_MBIN64S: |
| break; |
| |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32U: |
| { |
| // The MBIN16S operand is casted to a 64-bit value before the comp is |
| // performed. Until we have 64-bit comparison support, we can only |
| // do a little here. |
| if (inst->getROps()[0]->isConst()) { |
| Int64 val = getIntConstValue(inst->getROps()[0]); |
| if (val < 0) |
| return FALSE; |
| |
| // Positive value found that can be used in a MBIN32U comparison. |
| } |
| else |
| return FALSE; |
| |
| break; |
| } |
| |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S: |
| break; |
| |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16S: |
| break; |
| |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16S: |
| break; |
| |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16S: |
| break; |
| |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16S: |
| break; |
| |
| case PCIT::EQ_MBIN32S_MASCII_MASCII: |
| case PCIT::NE_MBIN32S_MASCII_MASCII: |
| case PCIT::LT_MBIN32S_MASCII_MASCII: |
| case PCIT::GT_MBIN32S_MASCII_MASCII: |
| case PCIT::LE_MBIN32S_MASCII_MASCII: |
| case PCIT::GE_MBIN32S_MASCII_MASCII: |
| break; |
| |
| case PCIT::COMP_MBIN32S_MASCII_MASCII_IBIN32S_IBIN32S_IBIN32S: |
| case PCIT::COMP_MBIN32S_MATTR5_MATTR5_IBIN32S: |
| break; |
| |
| case PCIT::SWITCH_MBIN32S_MBIN64S_MPTR32_IBIN32S_IBIN32S: |
| { |
| // Only in-lists supported, for now. |
| if (inst->code[8] & 0x1) |
| break; |
| |
| return (FALSE); |
| } |
| |
| case PCIT::SWITCH_MBIN32S_MATTR5_MPTR32_IBIN32S_IBIN32S: |
| { |
| // Only in-lists supported, for now. |
| if (inst->code[11] & 0x1) |
| break; |
| |
| return (FALSE); |
| } |
| |
| case PCIT::COMP_MBIN32S_MBIGS_MBIGS_IBIN32S_IBIN32S: |
| case PCIT::ADD_MBIGS_MBIGS_MBIGS_IBIN32S: |
| case PCIT::SUB_MBIGS_MBIGS_MBIGS_IBIN32S: |
| break; |
| |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S: |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S: |
| break; |
| |
| // case PCIT::SUB_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::SUB_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S: |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN16S: |
| break; |
| |
| /* 64-bit multiply not supported in libjit - need to call routine. */ |
| /* No support to downcast result to 16-bit type for now - not needed */ |
| //case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S: |
| //case PCIT::MUL_MBIN64S_MBIN32S_MBIN32S: |
| //case PCIT::MUL_MBIN64S_MBIN16S_MBIN32S: |
| //case PCIT::MUL_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S: |
| break; |
| |
| case PCIT::ADD_MFLT64_MFLT64_MFLT64: |
| case PCIT::SUB_MFLT64_MFLT64_MFLT64: |
| case PCIT::MUL_MFLT64_MFLT64_MFLT64: |
| case PCIT::DIV_MFLT64_MFLT64_MFLT64: |
| break; |
| |
| case PCIT::REPLACE_NULL_MATTR3_MBIN32S: |
| case PCIT::REPLACE_NULL_MATTR3_MBIN32U: |
| case PCIT::REPLACE_NULL_MATTR3_MBIN16S: |
| case PCIT::REPLACE_NULL_MATTR3_MBIN16U: |
| break; |
| |
| case PCIT::RETURN_IBIN32S: |
| case PCIT::RETURN: |
| break; |
| |
| case PCIT::MOVE_MBIN16U_MBIN8: |
| case PCIT::MOVE_MBIN32U_MBIN16U: |
| case PCIT::MOVE_MBIN32S_MBIN16U: |
| case PCIT::MOVE_MBIN64S_MBIN16U: |
| case PCIT::MOVE_MBIN32U_MBIN16S: |
| case PCIT::MOVE_MBIN32S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN32U: |
| case PCIT::MOVE_MBIN64S_MBIN32S: |
| break; |
| |
| case PCIT::MOVE_MFLT64_MBIN32S: |
| case PCIT::MOVE_MFLT64_MBIN16S: |
| break; |
| |
| case PCIT::MOVE_BULK: |
| break; |
| |
| case PCIT::MOVE_MBIN16U_MBIN16U: |
| case PCIT::MOVE_MBIN8_MBIN8: |
| case PCIT::MOVE_MBIN32U_MBIN32U: |
| case PCIT::MOVE_MBIN64S_MBIN64S: |
| case PCIT::MOVE_MBIN16U_IBIN16U: |
| case PCIT::MOVE_MBIN32S_IBIN32S: |
| break; |
| |
| case PCIT::MOVE_MATTR5_MATTR5: |
| { |
| PCodeOperand* read = inst->getROps()[0]; |
| PCodeOperand* write = inst->getWOps()[0]; |
| |
| // Since we plan on copying everyting (length + string) in one shot, |
| // make sure the vc lengths of the operands are the same. |
| if (read->getVcIndicatorLen() != write->getVcIndicatorLen()) |
| return FALSE; |
| |
| // For now, no support for temp varchars (since temp varchars will |
| // likely need to come from a separate temps area. |
| if (write->isTemp() || read->isTemp()) |
| return FALSE; |
| |
| // Also, target max length must be greater than that of source |
| if (read->getVcMaxLen() > write->getVcMaxLen()) |
| return FALSE; |
| |
| break; |
| } |
| |
| case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S: |
| { |
| // FIX: assert for now that write operand should be a temp |
| assert(inst->getWOps()[0]->isTemp()); |
| |
| // Just don't support case with nullable varchar in packed format, |
| // since that requires an extra level of indirection when accessing |
| // the null indicator -- not expensive/complicated to implement, but |
| // rare enough to want to avoid. |
| |
| PCodeOperand* src = inst->getROps()[0]; |
| if ((src->getOffset() == -1) && !src->forAlignedFormat()) |
| return FALSE; |
| |
| break; |
| } |
| |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MFLT64_MFLT64: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN32S_MBIN32S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S: |
| { |
| // Make sure that this is nullable before we proceed |
| if (!inst->code[7]) |
| return FALSE; |
| |
| break; |
| } |
| |
| case PCIT::SUM_MFLT64_MFLT64: |
| case PCIT::SUM_MBIN32S_MBIN32S: |
| case PCIT::SUM_MBIN64S_MBIN64S: |
| case PCIT::SUM_MBIN64S_MBIN32S: |
| break; |
| |
| case PCIT::STRLEN_MBIN32U_MATTR5: |
| { |
| // Only if we're dealing with a varchar (since fixed-chars should be |
| // optimized anyways to just return constant length) |
| if (inst->getROps()[0]->isVarchar()) |
| break; |
| |
| return FALSE; |
| } |
| |
| #if 0 |
| // |
| // SUBSTR should be fully-implemented, but testing may still be needed. |
| // |
| case PCIT::SUBSTR_MATTR5_MATTR5_MBIN32S_MBIN32S: |
| { |
| PCodeOperand *op1, *op2 = NULL; |
| |
| // Assert that result is a varchar |
| assert(inst->getWOps()[0]->isVarchar()); |
| |
| op1 = inst->getROps()[1]; |
| if (inst->getROps().entries() == 3) |
| op2 = inst->getROps()[2]; |
| |
| // To simplify code generation, both the start offset and the length, |
| // if provided, should be constants. |
| if (!op1->isConst() || (op2 && !op2->isConst())) |
| return FALSE; |
| |
| // To simplify code generation, do not process if the start point |
| // provided is negative or 0. |
| if (getIntConstValue(op1) <= 0) |
| return FALSE; |
| |
| // Also, some bozo may put 0 for the for length - just ignore that, |
| // even though the answer will always be an empty string. |
| if (op2 && (getIntConstValue(op2) <= 0)) |
| return FALSE; |
| |
| break; |
| } |
| #endif |
| |
| #if 0 |
| case PCIT::POS_MBIN32S_MATTR5_MATTR5: |
| { |
| // Only do this if pattern string is a constant |
| if (inst->getROps()[0]->isConst()) |
| break; |
| |
| return FALSE; |
| } |
| #endif |
| |
| |
| case PCIT::MOVE_MBIN32S: |
| { |
| // Only supported if RETURN follows it (as it always should) |
| if (inst->next && (inst->next->code[0] == PCIT::RETURN)) |
| break; |
| |
| return FALSE; |
| } |
| |
| |
| case PCIT::MOVE_MBIN8_MBIN8_IBIN32S: |
| { |
| // With genUnalignedMemcpy() available, the jit's version of memcpy |
| // is not needed, and so no external calls will be made. |
| break; |
| #if 0 |
| // Only support if it's guaranteed to be inlined |
| if (inst->getWOps()[0]->isVar() && inst->getROps()[0]->isVar() && |
| inst->getROps()[0]->getLen() <= 32) |
| break; |
| |
| return FALSE; |
| #endif |
| } |
| |
| case PCIT::HASHCOMB_BULK_MBIN32U: |
| break; |
| |
| case PCIT::HASH_MBIN32U_MATTR5: |
| case PCIT::HASH_MBIN32U_MPTR32_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN16_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN32_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN64_IBIN32S_IBIN32S: |
| { |
| // Is it possible that we're hashing constants?? Fold that sh!%@#t ! |
| assert (!inst->getROps()[0]->isConst()); |
| |
| // Only if source is a var. Dealing with temps can be messy since |
| // we would have to have the address of it and walk through it one |
| // byte at a time - doable, but we shouldn't expect to see temps. |
| if (!inst->getROps()[0]->isVar()) |
| return FALSE; |
| |
| // If we're hashing a fixed string, only support it for reasonable |
| // sizes (TODO: until code is written to make the hash a loop). |
| if ((inst->getOpcode() == PCIT::HASH_MBIN32U_MPTR32_IBIN32S_IBIN32S) && |
| (inst->getROps()[0]->getLen() > 1000)) |
| return FALSE; |
| |
| break; |
| } |
| |
| case PCIT::MINMAX_MBIN8_MBIN8_MBIN32S_IBIN32S: |
| break; |
| |
| case PCIT::RANGE_MFLT64: |
| break; |
| |
| case PCIT::LE_MBIN32S_MFLT64_MFLT64: |
| case PCIT::GE_MBIN32S_MFLT64_MFLT64: |
| case PCIT::LT_MBIN32S_MFLT64_MFLT64: |
| case PCIT::GT_MBIN32S_MFLT64_MFLT64: |
| case PCIT::EQ_MBIN32S_MFLT64_MFLT64: |
| case PCIT::NE_MBIN32S_MFLT64_MFLT64: |
| break; |
| |
| case PCIT::OPDATA_MPTR32_IBIN32S: |
| case PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S: |
| case PCIT::OPDATA_MBIN16U_IBIN32S: |
| case PCIT::OPDATA_MATTR5_IBIN32S: |
| break; |
| |
| case PCIT::CLAUSE_EVAL: |
| { |
| // on 64-bit the clause pointer is in code[1] and code[2] |
| ex_clause* clause = (ex_clause*)*(Long*)&(inst->code[1]); |
| NABoolean processNulls = inst->code[1 + PCODEBINARIES_PER_PTR]; |
| |
| // Only certain clause eval instructions will be supported for now. |
| switch (clause->getClassID()) { |
| case ex_clause::AGGR_MIN_MAX_ID: |
| { |
| // This clause must not call process nulls when evaluated |
| if (!processNulls) { |
| // Can only tolerate certain types for now. |
| if (isSupportedClauseOperandType(clause->getOperand(0))) |
| break; |
| |
| } |
| |
| return FALSE; |
| } |
| |
| case ex_clause::COMP_TYPE: |
| { |
| // No special nulls allowed for now. |
| if (clause->isSpecialNulls()) |
| return FALSE; |
| |
| switch (((ex_comp_clause*)clause)->getInstruction()) { |
| case NE_DATETIME_DATETIME: |
| case EQ_DATETIME_DATETIME: |
| case LT_DATETIME_DATETIME: |
| case GT_DATETIME_DATETIME: |
| case LE_DATETIME_DATETIME: |
| case GE_DATETIME_DATETIME: |
| { |
| // Only support standard types |
| long dtCode = |
| ((ExpDatetime*)(clause->getOperand(1)))->getPrecision(); |
| |
| // The lengths of the source operands must be the same. |
| if ((clause->getOperand(1)->getLength()) != |
| (clause->getOperand(1)->getLength())) |
| return FALSE; |
| |
| switch (dtCode) |
| { |
| case REC_DTCODE_DATE: |
| case REC_DTCODE_TIME: |
| case REC_DTCODE_TIMESTAMP: |
| break; |
| default: |
| return FALSE; |
| } |
| break; |
| } |
| |
| default: |
| return FALSE; |
| } |
| |
| break; |
| } |
| |
| default: |
| return FALSE; |
| } |
| |
| break; |
| } |
| |
| case PCIT::CONCAT_MATTR5_MATTR5_MATTR5: |
| { |
| Int32 src1Len = inst->getROps()[0]->getVcMaxLen(); |
| Int32 src2Len = inst->getROps()[1]->getVcMaxLen(); |
| Int32 resLen = inst->getWOps()[0]->getVcMaxLen(); |
| |
| Int32 maxSize = src1Len + src2Len; |
| |
| // If the max length of the target operand is less than the sum of |
| // the lengths of the source operands, do not support. Note, this is |
| // an easy thing to support, but in almost all the cases the tgt len |
| // should be big enough. |
| if (resLen < maxSize) { |
| assert(FALSE); |
| return FALSE; |
| } |
| |
| break; |
| } |
| |
| case PCIT::GENFUNC_MATTR5_MATTR5_IBIN32S: |
| { |
| if ((inst->code[11] == ITM_UPPER) || (inst->code[11] == ITM_LOWER)) |
| break; |
| |
| return FALSE; |
| } |
| |
| default: |
| return FALSE; |
| } |
| } ENDFE_INST_IN_BLOCK |
| } ENDFE_BLOCK_REV_DFO |
| |
| return TRUE; |
| } |
| |
| jit_type_t PCodeOperand::getJitType() |
| { |
| switch (operandType_) { |
| case PCIT::MBIN8: |
| return jit_type_ubyte; |
| case PCIT::MBIN16U: |
| return jit_type_ushort; |
| case PCIT::MBIN16S: |
| return jit_type_short; |
| case PCIT::MBIN32U: |
| return jit_type_uint; |
| case PCIT::MBIN32S: |
| return jit_type_int; |
| case PCIT::MBIN64S: |
| return jit_type_long; |
| case PCIT::MASCII: |
| case PCIT::MATTR5: |
| case PCIT::MBIGS: |
| return jit_type_void_ptr; |
| case PCIT::MPTR32: |
| { |
| if (nullBitIndex_ != -1) |
| return jit_type_ubyte; |
| else |
| return jit_type_void_ptr; |
| } |
| case PCIT::MFLT64: |
| return jit_type_float64; |
| } |
| |
| // No other types supported |
| assert(FALSE); |
| |
| return jit_type_void; |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| // |
| // FIX: This routine was added because of a bug in libjit involving a register |
| // allocation bug and integer promotion. If a 32-bit value X is promoted to a |
| // 64-bit value, so that it can be added to an existing 64-bit value Y, then |
| // the "sar" instruction is used to extend the value. Libjit's allocator then |
| // mistakingly confuses the shifted value to replace the 32-bit value itself. |
| // If we end up reusing/referencing the 32-bit value elsewhere, the wrong jit |
| // value will get used. See fullstack2/TEST023. Also, included below is a |
| // simple example that shows the problem: |
| // |
| // temp1 = jit_insn_load_relative(function, s, 0, jit_type_long); |
| // temp2 = jit_insn_load_relative(function, s, 8, jit_type_int); |
| // temp3 = jit_insn_add(function, temp1, temp2); |
| // jit_insn_store_relative(function, s, 12, temp3); |
| // |
| // temp4 = jit_insn_convert(function, temp2, jit_type_long, 0); |
| // jit_insn_store_relative(function, t, 0, temp4); |
| // |
| // jit_insn_return(function, tempZero); |
| // |
| // If a newer version of libjit comes our way, or if a patch is made to fix the |
| // problem, this routine is not needed. For now, it should be called whenever |
| // a source operand needs to be promoted to a 64-bit value before use. It |
| // really is only needed if the operand is live after the use, but there's no |
| // harm in removing/clearing the saved jit values at this point. |
| // |
| |
| void PCodeOperand::clearJitValues(PCodeCfg* cfg) |
| { |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| return; // Routine NOT needed for LLVM....we hope! |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| if (operand != this) |
| return operand->clearJitValues(cfg); |
| |
| jitValue_ = NULL; |
| jitValuePtr_ = NULL; |
| jitValueBlock_ = NULL; |
| #endif /* NA_LINUX_LIBJIT */ |
| } |
| |
| // |
| // setJitValue() - see code for what this does. |
| // |
| // FIX: Overlapped types can have problems |
| // NOTE: It is unknown if this is a problem when using LLVM |
| // as opposed to LIBJIT. |
| // |
| void PCodeOperand::setJitValue( PCodeCfg * cfg |
| , IRBldr_t * Bldr |
| , jit_value_t val |
| , PCodeBlock * b |
| , NABoolean noSave = FALSE |
| ) |
| { |
| #if NExprDbgLvl >= VV_NO |
| char NExBuf[500]; |
| #endif |
| // If this was called to store into a non-temp, storeJitValue should be |
| // called instead. |
| if (!isTemp()) |
| ////return storeJitValue(cfg, f, jit_value_get_type(val), val, b, NULL, noSave); |
| return storeJitValue(cfg, Bldr, val->getType(), val, b, NULL, noSave ); |
| |
| // Also call storeJitValue if it's a temp and the temp already has a different |
| // jit value associated with it. |
| if (isTemp() && (jitValue_ != val)) |
| ////return storeJitValue(cfg, f, jit_value_get_type(val), val, b, NULL, noSave); |
| return storeJitValue(cfg, Bldr, val->getType(), val, b, NULL, noSave ); |
| |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| |
| CDPT2( "VV0c00: ", VV_BD, "In setJitValue(): operand=%p, this=%p\n", operand, this ); |
| |
| if (operand != this) |
| return operand->setJitValue(cfg, Bldr, val, b, noSave); |
| |
| // If we are directly told not to save the jit values, don't! |
| if (!noSave) { |
| jitValue_ = val; |
| |
| CDPT2( "VV0c10: ", VV_BD, "In setJitValue(): setting jitValue_ in PCodeOp " |
| "at %p to %p\n", this, jitValue_ ); |
| CDPT1( "VV0c11: ", VV_BD, "jitValue_'s Type ID is %d\n", |
| (int) val->getType()->getTypeID() ); |
| CDPT2( "VV0c12: ", VV_BD, "In setJitValue(): setting jitValueBlock_ = " |
| "%p for PCOp = %p\n", b , this); |
| jitValueBlock_ = b; |
| } |
| } |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| // FIX: Overlapped types can have problems |
| void PCodeOperand::setJitValue(PCodeCfg* cfg, |
| jit_function_t f, |
| jit_value_t val, |
| PCodeBlock* b, |
| NABoolean noSave = FALSE) |
| { |
| // If this was called to store into a non-temp, storeJitValue should be |
| // called instead. |
| if (!isTemp()) |
| return storeJitValue(cfg, f, jit_value_get_type(val), val, b, NULL, noSave); |
| |
| // Also call storeJitValue if it's a temp and the temp already has a different |
| // jit value associated with it. |
| if (isTemp() && (jitValue_ != val)) |
| return storeJitValue(cfg, f, jit_value_get_type(val), val, b, NULL, noSave); |
| |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| if (operand != this) |
| return operand->setJitValue(cfg, f, val, b, noSave); |
| |
| // If we are directly told not to save the jit values, don't! |
| if (!noSave) { |
| jitValue_ = val; |
| jitValueBlock_ = b; |
| } |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |
| // |
| // isSupportedClauseOperandType() - determine if the NE code |
| // supports this particular PCIT::CLAUSE_EVAL's operand. |
| // |
| NABoolean PCodeCfg::isSupportedClauseOperandType(exp_Attributes* attr) |
| { |
| switch(PCIT::getMemoryAddressingMode(attr->getDatatype())) |
| { |
| case PCIT::MBIN8: |
| case PCIT::MBIN16U: |
| case PCIT::MBIN16S: |
| case PCIT::MBIN32U: |
| case PCIT::MBIN32S: |
| case PCIT::MBIN64S: |
| case PCIT::MASCII: |
| case PCIT::MATTR3: |
| // case PCIT::MATTR5: // Need to fix MIN_MAX for varchars first |
| |
| #ifdef NA_LINUX_LIBJIT |
| case PCIT::MFLT64: // Not supported by LLVMJIT yet |
| case PCIT::MBIGS: // Not supported by LLVMJIT yet |
| #endif /* NA_LINUX_LIBJIT */ |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| void PCodeCfg::setupClauseOperand(PCodeCfg* cfg, |
| OPLIST& opList, |
| PCodeOperand** opData, |
| Int32 index, |
| ex_clause* clause) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| Int32 len; |
| PCIT::AddressingMode am; |
| DPT5( "VV0a00: ", VV_XD, |
| "In setupClauseOperand(), cfg=%p, opList at %p, opData at %p, " |
| "index=%d, clause at %p\n", cfg, &opList[0], opData, index, clause ); |
| |
| // Ignore calls to setup the operand for varchar lengths, since that is not |
| // useful once we have the actual column attribute. |
| if ((index >= 5) && (index < 10)) |
| { |
| DPT1( "VV0a01: ", VV_XD, |
| "Returning from setupClauseOperand() because index = %d - " |
| "indicating varchar\n", index); |
| return; |
| } |
| |
| // Get the attribute pointer corresponding to this clause operand |
| Int32 opIndex = index % ex_clause::MAX_OPERANDS; |
| exp_Attributes* attr = clause->getOperand(opIndex); |
| |
| // Get the old (pcode opts) operand from the opList and clear the list now. |
| |
| #if NExprDbgLvl >= VV_XD |
| for (Int32 iii = 0; iii < opList.entries(); iii++ ) |
| DPT2( "VV0a10: ", VV_XD, "At start of setupClauseOperand(), opList[%d] = " |
| "%p\n", iii, opList[iii]); |
| #endif |
| |
| PCodeOperand* operand = opList[0]; |
| opList.clear(); |
| DPT1( "VV0a20: ", VV_XD, "AFTER clearing opList, 'operand=OLD opList[0] == " |
| "%p\n", operand ); |
| |
| #if NExprDbgLvl >= VV_XD |
| for (Int32 jjj = 0; jjj < opList.entries(); jjj++ ) |
| DPT2( "VV0a30: ", VV_XD, "AFTER clearing opList, opList[%d] = %p\n", |
| jjj, opList[jjj]); |
| #endif |
| |
| // Set up a bogus pcode array needed to call ::addOperand later on. |
| PCodeBinary fakePCode[2] = { operand->getStackIndex(), operand->getOffset() }; |
| |
| // Process things separately if we're getting the null indicator. |
| if(index < 5) { |
| am = ((attr->getNullBitIndex() != -1) ? PCIT::MPTR32 : PCIT::MBIN16S); |
| len = (am == PCIT::MPTR32) ? -1 : 2; |
| DPT3( "VV0a40: ", VV_XD, " AM = PCIT::%d, len=%d, index=%d\n", |
| (int)am, len, index ); |
| |
| cfg->addOperand(fakePCode, opList, 0, 1, attr->getNullBitIndex(),am,len,-1); |
| } |
| // Now we're processing any other type (e.g string, int, floats, etc). |
| else if (attr->getVCIndicatorLength() > 0) { |
| am = PCIT::MATTR5; |
| len = attr->getLength(); |
| DPT2( "VV0a50: ", VV_XD, " AM = PCIT::%d, index=%d\n", (int)am, index ); |
| |
| cfg->addOperand(fakePCode, opList, 0, 1, -1, am, len, attr->getVoaOffset()); |
| } |
| else { |
| switch (attr->getLength()) { |
| case 1: |
| case 2: |
| case 4: |
| case 8: |
| am = PCIT::getMemoryAddressingMode(attr->getDatatype()); |
| break; |
| default: |
| am = PCIT::MASCII; |
| break; |
| } |
| |
| DPT3("VV0a60: ", VV_XD, " AM = PCIT::%d, index=%d, attrLen = %d\n", |
| (int)am , index, attr->getLength()); |
| |
| DPT2("VV0a80: ", VV_XD, " attr->getDatatype() = %d, " |
| "PCIT::getMemoryAddressingMode(attr->getDatatype()= %d\n", |
| attr->getDatatype(), PCIT::getMemoryAddressingMode(attr->getDatatype()) ); |
| |
| cfg->addOperand(fakePCode, opList, 0, 1, -1, am, attr->getLength(), -1); |
| } |
| |
| // Update the opData array with the new operand. |
| opData[index] = opList[0]; |
| DPT2("VV0a90: ", VV_XD, " JUST UPDATED opData[index = %d] to be %p\n", |
| index, opData[index] ); |
| DPT2("VV0a98: ", VV_XD, " At END of setupClauseOperand, opData[%d] == %p\n", |
| index, opData[index]); |
| PCodeOperand *PCOp = opData[index]; |
| |
| DPT6("VV0a99: ", VV_XD, " DETAILS OF PCodeOperand are: \n" |
| "stackIndex_ = %d, offset_ = %d, len_=%d, operandType_=%d, " |
| "nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| } |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| |
| // |
| // IR_LoadRelativeWithType() - generate a "load" instruction to load a value |
| // at a specified byte offset from where the specified pointer points. |
| // The "typeToLoad" argument specifies what kind of "load" to generate. |
| // |
| // NOTE: Although this routine generates a "load" instruction, it returns |
| // the pointer to that instruction as a jit_value_t (i.e. an llvm::Value). |
| // The caller can use this jit_value_t AS IF we had returned the value |
| // that would actually be fetched by the load! Basically, what we are |
| // really doing is NOT generating a "load" instruction, but rather |
| // teaching the Intermediate Representation generator HOW TO materialize |
| // the value at runtime for the object (byte, short, int, or whatever) |
| // that would be fetched if a "load" instruction was actually done. |
| // It is for this reason that the caller can use the returned jit_value_t |
| // AS IF we had returned the value of the object. |
| // |
| jit_value_t PCodeCfg::IR_LoadRelativeWithType( IRBldr_t * Bldr |
| , jit_value_t int8p |
| , Int64 byteOffset |
| , jit_type_t typeToLoad |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| DPT0( "VV0100: ", VV_BD, "In IR_LoadRelativeWithType\n" ); |
| |
| jit_value_t int8p2, byOff, finalPtr, rtnVal ; |
| |
| if ( byteOffset == 0 ) |
| int8p2 = int8p ; |
| else |
| { |
| byOff = ConstantInt::get( int64Ty_, byteOffset ) ; |
| |
| DPT1("VV0101: ", VV_VD, |
| "int8p2 = Bldr->CreateGEP( int8p, byOff = %ld)\n", byteOffset ); |
| int8p2 = Bldr->CreateGEP( int8p, byOff ); |
| } |
| |
| DPT0("VV0102: ", VV_VD, |
| "finalPtr = Bldr->CreatePointerCast(int8p2, typeToLoad->getPointerTo() )\n" ); |
| finalPtr = Bldr->CreatePointerCast( int8p2, typeToLoad->getPointerTo() ); |
| |
| DPT0("VV0103: ", VV_VD, |
| "Load_inst = Bldr->CreateLoad( finalPtr, 'DataVal' )\n" ); |
| LoadInst * Load_inst = Bldr->CreateLoad( finalPtr, "DataVal" ); |
| |
| rtnVal = Load_inst ; |
| return( rtnVal ); |
| } |
| |
| // |
| // IR_StoreRelativeWithType() - generate a "store" instruction to store a |
| // value at a specified byte offset from where the specified pointer points. |
| // The "typeToStore" argument specifies what kind of "store" to generate. |
| // |
| void PCodeCfg::IR_StoreRelativeWithType( IRBldr_t * Bldr |
| , jit_value_t val |
| , jit_value_t tgt8ByPtr |
| , Int64 byteOffset |
| , jit_type_t typeToStore |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| jit_value_t tgt8ByPtr2, byOff, finalTgt ; |
| |
| DPT0( "VV0200: ", VV_BD, "In IR_StoreRelativeWithType\n" ); |
| |
| if ( byteOffset == 0 ) |
| tgt8ByPtr2 = tgt8ByPtr ; |
| else |
| { |
| byOff = ConstantInt::get( int64Ty_, byteOffset ) ; |
| |
| DPT1( "VV0201: ", VV_VD, |
| "Tgt_8p2 = Bldr->CreateGEP( tgt8ByPtr, byOff = %ld ) \n", byteOffset ); |
| tgt8ByPtr2 = Bldr->CreateGEP( tgt8ByPtr, byOff ); |
| } |
| |
| DPT0( "VV0202: ", VV_VD, |
| "finalTgt = Bldr->CreatePointerCast(tgt8ByPtr2, typeToStore->getPointerTo() )\n" ); |
| finalTgt = Bldr->CreatePointerCast(tgt8ByPtr2, typeToStore->getPointerTo() ); |
| |
| DPT0( "VV0202: ", VV_VD, |
| "Bldr->CreateStore( val, finalTgt )\n" ); |
| Bldr->CreateStore( val, finalTgt ); |
| } |
| |
| // |
| // getJitValue() - generate code to fetch the specified value. |
| // |
| // FIX: Overlapped types can have problems too |
| // NOTE: It is unknown if this is a problem when using LLVM |
| // as opposed to LIBJIT. |
| // |
| jit_value_t PCodeOperand::getJitValue( PCodeCfg * cfg |
| , IRBldr_t * Bldr |
| , jit_type_t IRtype |
| , PCodeBlock * blk |
| , PCodeOperand * orig = NULL |
| , NABoolean noSave = FALSE |
| ) |
| { |
| #if NExprDbgLvl >= VV_NO |
| char NExBuf[500]; |
| #endif |
| CDPT1( "VV0300: ", VV_BD, "GOT into getJitValue() on PCode Operand at %p\n", this ); |
| |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| |
| CDPT2( "VV0301: ", VV_BD, "In getJitValue(): operand=%p, this=%p\n", operand, this ); |
| |
| if (operand != this) |
| { |
| return operand->getJitValue(cfg, Bldr, IRtype, blk, this, noSave); |
| } |
| |
| // Make sure we properly indicate that this object *is* the original one. |
| if (orig == NULL) |
| orig = this; |
| |
| // |
| // Get pointer to operand, if that's what is needed |
| // |
| |
| if ( IRtype == cfg->getInt1PtrTy() ) { |
| |
| CDPT0( "VV0310: ", VV_BD, "In getJitValue, IRtype == cfg->getInt1PtrTy()\n"); |
| CDPT1( "VV0311: ", VV_BD, "jitValuePtr_ = %p\n", jitValuePtr_ ); |
| |
| // If already defined somewhere, perhaps it can be reused? |
| if (jitValuePtr_) { |
| assert(jitValuePtrBlock_ != NULL); |
| |
| // If the PCBlock given in jitValuePtrBlock_ dominates PCBlock blk, |
| // then we are assured that jitValuePtr_ is valid. |
| // |
| if (blk->onesVector.testBit(jitValuePtrBlock_->getBlockNum())) |
| return jitValuePtr_; |
| else |
| jitValuePtr_ = NULL; |
| } |
| CDPT1( "VV0315: ", VV_BD, "jitValuePtr_ is NOW = %p\n", jitValuePtr_); |
| |
| // Non-native temps will be accessed directly from the passed in temps |
| // area. If that temp was previously defined as a jit value (e.g. size of |
| // temp fit native storage container), then we skip to the else clause so |
| // the address is simply taken for the jit value. |
| if (isVar() || isConst() || (!jitValue_ && orig->isNonNativeTemp())) { |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| |
| CDPT2( "VV0317: ", VV_BD, "In getJitValue, stackIndex_ = %d, parm1 at %p \n", stackIndex_ , parm1 ); |
| CDPT0( "VV0320: ", VV_BD, "param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() )\n" ); |
| |
| jit_value_t param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() ); |
| |
| CDPT1( "VV0321: ", VV_BD, "In getJitValue, param [Int8Ptr] at %p \n", param ); |
| CDPT0( "VV0322: ", VV_BD, "In getJitValue, found isVar() || isConst() || ...\n" ); |
| |
| #if NExprDbgLvl >= VV_BD |
| if (isVar()) |
| CDPT0( "VV0323: ", VV_BD, "In getJitValue, found isVar() TRUE\n" ); |
| if (isConst()) |
| CDPT0( "VV0324: ", VV_BD, "In getJitValue, found isConst() TRUE\n" ); |
| if (isNonNativeTemp()) |
| CDPT0( "VV0325: ", VV_BD, "In getJitValue, found isNonNativeTemp() TRUE\n" ); |
| #endif |
| CDPT1( "VV0326: ", VV_BD, "In getJitValue, getType() returns %d\n", getType() ); |
| |
| // For varchars we return a pointer to the start of length indicator. |
| if (getType() == PCIT::MATTR5) { |
| |
| // If we're not dealing with a varchar, or if it is the first varchar, |
| // we don't need to go through the VOA offset. |
| if (!isVarchar() || (getVoaOffset() == -1)) { |
| // jitValuePtr_ = |
| // jit_insn_add_relative(param, (offset_ - vcIndicatorLen_)); |
| |
| jit_value_t tmp1 = ConstantInt::get( cfg->getInt64Ty(), |
| offset_ - vcIndicatorLen_ ) ; |
| CDPT2( "VV0330: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreateGEP( param, tmp1 = %d - %d )\n", |
| offset_, vcIndicatorLen_ ); |
| |
| jitValuePtr_ = Bldr->CreateGEP( param, tmp1 ); |
| } |
| else |
| { |
| jit_type_t MyTy = ((vcIndicatorLen_ == 2) |
| // ? jit_type_ushort : jit_type_uint); |
| ? cfg->getInt16Ty() : cfg->getInt32Ty()); |
| |
| //// jit_value_t v = jit_insn_load_relative(f, param, voaOffset_, MyTy); |
| |
| jit_value_t vcLen = cfg->IR_LoadRelativeWithType( Bldr, param, |
| voaOffset_, MyTy ); |
| |
| // |
| // NOTE: The 16-bit or 32-bit offset that we just "loaded" should be |
| // treated as an *unsigned* value so that we don't reference some |
| // negative offset from the beginning of the string/object/structure. |
| // So, here we generate a Zero-Extend instruction to get the offset |
| // extended out to 64 bits before it is added to the address of the object. |
| // |
| jit_value_t unsignedVcLen ; |
| |
| CDPT0( "VV0334: ", VV_BD, |
| "unsignedVcLen = Bldr->CreateZExt( vcLen, cfg->getInt64Ty() , 'ZExtVcLen' )\n" ); |
| unsignedVcLen = Bldr->CreateZExt( vcLen, cfg->getInt64Ty() , "ZExtVcLen" ); |
| |
| //// jitValuePtr_ = jit_insn_add(f, param, v); |
| |
| CDPT0( "VV0335: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreateGEP( param, unsignedVcLen )\n" ); |
| jitValuePtr_ = Bldr->CreateGEP( param, unsignedVcLen ); |
| |
| // Now set up pointer, moving past null indicator if required. |
| if (vcNullIndicatorLen_) |
| { |
| //// jitValuePtr_ = jit_insn_add_relative(f, jitValuePtr_, |
| //// vcNullIndicatorLen_); |
| |
| CDPT0( "VV0340: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreatePointerCast( jitValuePtr_, cfg->getInt8PtrTy() )\n" ); |
| jitValuePtr_ = Bldr->CreatePointerCast( jitValuePtr_, cfg->getInt8PtrTy() ); |
| |
| jit_value_t NI_len = ConstantInt::get( cfg->getInt64Ty(), vcNullIndicatorLen_ ) ; |
| |
| // Now make jitValuePtr_ point to the first byte AFTER the Null Indicator |
| |
| CDPT0( "VV0341: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreateGEP( jitValuePtr_ , NI_len )\n" ); |
| jitValuePtr_ = Bldr->CreateGEP( jitValuePtr_ , NI_len ); |
| } |
| } |
| CDPT0( "VV0345: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreatePointerCast( jitValuePtr_, cfg->getInt8PtrTy() )\n" ); |
| jitValuePtr_ = Bldr->CreatePointerCast( jitValuePtr_, cfg->getInt8PtrTy() ); |
| |
| } // End: if (getType() == PCIT::MATTR5) |
| |
| else { |
| //// jitValuePtr_ = jit_insn_add_relative(f, param, offset_); |
| |
| jit_value_t tmp1 = ConstantInt::get( cfg->getInt64Ty(), offset_ ) ; |
| |
| CDPT1( "VV0348: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreateGEP( param, tmp1 = %d )\n", offset_ ); |
| jitValuePtr_ = Bldr->CreateGEP( param, tmp1 ); |
| } |
| |
| } // End: if (isVar() || isConst() || (!jitValue_ && orig->isNonNativeTemp())) |
| |
| else { |
| |
| CDPT1( "VV0350: ", VV_BD, "PCodeOperand::getType() RETURNED %d\n", (int)getType() ); |
| |
| // Normally we would force the jitValue_ to be defined if we're attempting |
| // to get it. However, in some cases (like FILL_MEM_BYTES) we make a |
| // a call to get it first so that things like the vc length can be written |
| // to it first. |
| // FIX: fix this so that we can continue to assert that jitValue_ should |
| // be defined first. Fixing it involves having storeJitValue support |
| // all possible stores (vc lengths, actual values, etc.). |
| |
| // Must be called and it must already be defined |
| |
| if (!jitValue_) { |
| // We reached a situation that we can't support. For example, we could |
| // having something like this: |
| // |
| // B1: [2,0] = ... |
| // Branch B3 |
| // B2: [2,0] = ... |
| // B3: = [2,0] |
| // |
| // If we allocated space for [2,0] in B1, and then do the same in B2, |
| // which one do we use for B3? Also, if we try to allocate space for |
| // [2,0] in B3, then it would be completely wrong. |
| |
| cfg->setJitFailureSeen(); |
| CDPT0( "VV0352: ", VV_BD, "setJitFailureSeen() was just called!\n" ); |
| |
| // And for the sake of nothing else failing along the way, use a |
| // bogus value to return. |
| return cfg->getFalse_JitVal_() ; |
| } |
| |
| assert (jitValue_ && isTemp()); |
| |
| #if 0 /* NOT NEEDED WITH LLVM */ |
| // Temporary value needs to be addressable. |
| jit_value_set_addressable(jitValue_); |
| #endif |
| |
| // Return the address of this temp variable. |
| |
| // jitValuePtr_ = jit_insn_address_of(f, jitValue_); |
| |
| CDPT0( "VV0355: ", VV_BD, |
| "jitValuePtr_ = jitValue_ ; // USE jitValue_ AS ITS ADDRESS\n"); |
| jitValuePtr_ = jitValue_ ; // For LLVM, we can use the Value ptr *AS* its address! |
| |
| CDPT2( "VV0357: ", VV_BD, "jitValuePtr_ at %p is POINTING to Value rep by " |
| "jitValue_ at %p\n", |
| jitValuePtr_, jitValue_ ); |
| CDPT1( "VV0359: ", VV_BD, "CREATED Value's Type ID is %d\n", |
| (int) jitValue_->getType()->getTypeID() ); |
| |
| // If the jitValue_ was not defined in this current block, then the safe |
| // thing to do is simply return the address of jitValue, but *do not* |
| // save the pointer in jitValuePtr_, since that will lead to confusion |
| // on what was defined where. |
| if (jitValuePtrBlock_ != blk) { |
| jit_value_t temp = jitValuePtr_; |
| jitValuePtr_ = NULL; |
| |
| CDPT1( "VV0360: ", VV_BD, "returning tempVal = %p\n", temp ); |
| return temp; |
| } |
| |
| } //End: else [i.e. NOT ((isVar() || isConst() || ... ] |
| |
| CDPT2( "VV0361: ", VV_BD, "In getJitValue(): setting jitValuePtrBlock_ = %p " |
| "for PCop = %p\n", blk, this ); |
| jitValuePtrBlock_ = blk; |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) |
| { |
| jit_value_t tempVal = jitValuePtr_; |
| jitValueBlock_ = NULL; |
| jitValuePtrBlock_ = NULL; |
| |
| CDPT1( "VV0362: ", VV_BD, "In getJitValue(): NULLing jitValue_ in PCodeOp at %p\n", this ); |
| jitValue_ = jitValuePtr_ = NULL; |
| |
| CDPT1( "VV0364: ", VV_BD, "returning tempVal = %p\n", tempVal ); |
| |
| return tempVal; |
| } |
| |
| CDPT1( "VV0366: ", VV_BD, "returning jitValuePtr_ = %p\n", jitValuePtr_ ); |
| |
| return jitValuePtr_; |
| |
| } //End: if ( IRtype == cfg->getInt1PtrTy() ) |
| |
| CDPT2( "VV0368: ", VV_BD, "IRtype != cfg->getInt1PtrTy() for PCodeOp at %p " |
| "with jitValue_ = %p\n", this, jitValue_ ); |
| |
| // |
| // Get value of operand |
| // |
| |
| // If already defined somewhere, perhaps it can be reused? If it's a temp, |
| // however, then the assumption is that all uses have a def which reach it, |
| // and that def is available in jitValue_. |
| if (jitValue_) { |
| jit_type_t valType = jitValue_->getType() ; |
| |
| CDPT1( "VV0370: ", VV_BD, "jitValue_ != NULL, nullBitIndex_ = %d\n", nullBitIndex_ ); |
| CDPT2( "VV0372: ", VV_BD, "FOUND jitValue_ in PCodeOp at %p set to %p\n", |
| this, jitValue_ ); |
| CDPT2( "VV0374: ", VV_BD, |
| "In getJitValue(): valType->getTypeID() = %d, IRtype->getTypeID()=%d \n", |
| (int) valType->getTypeID(), (int) IRtype->getTypeID() ); |
| #if NExprDbgLvl >= VV_BD |
| if (valType->isPointerTy()) |
| CDPT1( "VV0376: ", VV_BD, "In getJitValue(): valType->getContainedType(0)->getTypeID() = %d\n", |
| (int) valType->getContainedType(0)->getTypeID() ); |
| #endif |
| |
| assert(jitValueBlock_ != NULL); |
| |
| CDPT1( "VV0376A: ", VV_BD, "In getJitValue(): jitValueBlock_ = %p\n", jitValueBlock_) ; |
| CDPT1( "VV0376A: ", VV_BD, "In getJitValue(): isTemp() = %x\n", (Int32) isTemp() ); |
| CDPT2( "VV0376A: ", VV_BD, "In getJitValue(): blk = %p, jitValueBlock Dominates blk = %x\n", |
| blk, (Int32) blk->onesVector.testBit(jitValueBlock_->getBlockNum()) ); |
| |
| // If the PCBlock given in jitValueBlock_ dominates PCBlock blk, |
| // then we are assured that jitValue_ is valid. |
| // |
| if ( (isTemp() || blk->onesVector.testBit(jitValueBlock_->getBlockNum())) && |
| (( valType->getTypeID() == IRtype->getTypeID() ) || |
| ( valType->isPointerTy() && |
| valType->getContainedType(0)->getTypeID() == IRtype->getTypeID() |
| ) || |
| ( isTemp() && valType->isPointerTy() && |
| valType->getContainedType(0)->isPointerTy() |
| ) |
| ) |
| ) |
| { |
| CDPT0( "VV0377: ", VV_BD, "Found jitValue_ != NULL and MAY be able to use it\n" ); |
| |
| // It's possible that we have some overlapping operands. The following |
| // deals with it (or at least for the majority of the cases where we see |
| // an overlap :() |
| // jit_type_t jitValType = jit_value_get_type(jitValue_); |
| // if (jit_type_get_size(jitValType) > jit_type_get_size(type)) |
| // return jit_insn_convert(f, jitValue_, type, 0); |
| |
| assert ( IRtype->getTypeID() == Type::IntegerTyID ); |
| |
| Int32 valBitWdth ; |
| jit_value_t actualVal = jitValue_ ; |
| |
| if ( valType->isPointerTy() ) |
| { |
| CDPT0( "VV0378: ", VV_BD, |
| "actualVal = Bldr->CreateLoad( jitValue_, 'loadTemp' )\n" ); |
| actualVal = Bldr->CreateLoad( jitValue_, "loadTemp" ) ; |
| |
| valBitWdth = actualVal->getType()->getIntegerBitWidth() ; |
| } |
| else |
| { |
| valBitWdth = valType->getIntegerBitWidth() ; |
| } |
| |
| if ( valBitWdth != IRtype->getIntegerBitWidth() ) |
| { |
| CDPT0( "VV0380: ", VV_BD, |
| "return( Bldr->CreateSExtOrTrunc( actualVal, (IntegerType *)IRtype, 'SExtOrTrunk' ) )\n" ); |
| return( Bldr->CreateSExtOrTrunc( actualVal, |
| (IntegerType *)IRtype, "SExtOrTrunk" ) ); |
| } |
| |
| return actualVal ; |
| |
| } // End: if ( (isTemp() || blk->onesVector.testBit(... |
| |
| CDPT1( "VV0382: ", VV_BD, "In getJitValue(): NULLing jitValue_ in PCodeOp at %p\n", this ); |
| |
| jitValue_ = NULL; |
| |
| } // End: if (jitValue_) |
| |
| // NOTE: If we get here, then either jitValue_ was NULL or |
| // we decided it was not valid. |
| |
| if (isConst()) { |
| |
| CDPT1( "VV0384: ", VV_BD, "isConst() is TRUE. Also - nullBitIndex_ = %d\n", nullBitIndex_ ); |
| |
| // |
| // FIX: the assumption right now is that only integers are considered for |
| // native expressions. That will change shortly. In the meantime, however, |
| // this implies that getIntConstValue() should be called on the operand to |
| // retrieve the constant value. |
| // |
| // FIX: getIntConstValue() should probably be "relaxed" a little so as to |
| // support MPTR32 and MFLT (both of which may be casted into integer types |
| // during same-sized moves). For now, work around by adding logic here. |
| // |
| |
| if ( IRtype == cfg->getInt64Ty() ) { |
| // MFLT64 can sometimes be the original type of the operand being sought |
| // after (e.g. PCIT::MFLT64_MFLT64 --> PCIT::MBIN64S_MBIN64S). Use the |
| // original operand to get the constant value. |
| // Likewise, we should use the original type in the case of MBIGS or MBIGU |
| // because PCODE optimization may change MBIG[SU]-type PCODE instructions |
| // to simpler instructions such as 64-bit move instructions. |
| |
| PCodeOperand* op = ((getType() == PCIT::MFLT64) || |
| (getType() == PCIT::MFLT32) || |
| (getType() == PCIT::MBIGS ) || |
| (getType() == PCIT::MBIGU ) |
| ) |
| ? orig : this; |
| |
| Int64 val = cfg->getIntConstValue(op); |
| |
| // jitValue_ = jit_value_create_long_constant(f, type, val); |
| jitValue_ = ConstantInt::get( IRtype, val ); |
| CDPT2( "VV0386: ", VV_BD, |
| "In getJitValue(): setting jitValue_ in PCodeOp at %p to %p\n", |
| this, jitValue_ ); |
| CDPT1( "VV0388: ", VV_BD, "In getJitValue(): CREATED Value's Type ID is %d\n", |
| (int) jitValue_->getType()->getTypeID() ); |
| } |
| else if (getType() == PCIT::MPTR32) { |
| // MPTR32 can sometimes be the original type of the operand being sought |
| // after (e.g. PCIT::MBIN8_MBIN8_IBIN32S --> PCIT::MBIN8_MBIN8). Use the |
| // original operand to get the constant value. |
| |
| Int32 val = (Int32)cfg->getIntConstValue(((orig) ? orig : this)); |
| // jitValue_ = jit_value_create_nint_constant(f, type, val); |
| |
| CDPT1( "VV0390: ", VV_BD, "In getJitValue(): setting jitValue_ to be a constant Int of %d\n", val ); |
| CDPT1( "VV0391: ", VV_BD, "In getJitValue(): and jitValue_'s bitWidth is %d\n", |
| IRtype->getIntegerBitWidth() ); |
| jitValue_ = ConstantInt::get( IRtype, val ); |
| |
| CDPT2( "VV0392: ", VV_BD, "In getJitValue(): setting jitValue_ in PCodeOp at %p to %p\n", |
| this, jitValue_ ); |
| CDPT1( "VV0394: ", VV_BD, "In getJitValue(): CREATED Value's Type ID is %d\n", |
| (int) jitValue_->getType()->getTypeID() ); |
| } |
| else if ( IRtype->isFloatTy() ) { |
| assert(0==245); // NEED TO add real code here when |
| // we want to use LLVM on Floating Pt |
| // related PCODE instructions |
| |
| // Unless the value is "1.0", libjit will store a double constant in |
| // memory, referenced via %ip, and that will blow us up at runtime. Get |
| // it from memory instead (if not 1.0) |
| #if 0 // FIX THIS when want to use LLVM on Floating Pt related PCODE instructions |
| double val = cfg->getFloatConstValue(((orig) ? orig : this)); |
| if (val == 1.0) |
| jitValue_ = jit_value_create_float64_constant(f, type, val); |
| else { |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| jit_value_t param = Bldr->CreatePointerCast(parm1, Int8PtrTy ); |
| jitValue_ = jit_insn_load_relative(f, param, offset_, type); |
| } |
| #endif // 0 |
| } |
| else { |
| Int32 val = (Int32)cfg->getIntConstValue(((orig) ? orig : this)); |
| // jitValue_ = jit_value_create_nint_constant(f, type, val); |
| jitValue_ = ConstantInt::get( IRtype , val ); |
| |
| CDPT2( "VV0396: ", VV_BD, "In getJitValue(): setting jitValue_ in PCodeOp at %p to %p\n", |
| this, jitValue_ ); |
| CDPT1( "VV0397: ", VV_BD, "CREATED Value's Type ID is %d\n", (int) jitValue_->getType()->getTypeID() ); |
| CDPT1( "VV0398: ", VV_BD, "CREATED Value's actual value is %d\n", val ); |
| } |
| |
| } // End: if (isConst()) |
| |
| else if (isVar()) { |
| |
| CDPT1( "VV0399: ", VV_BD, "nullBitIndex_ = %d\n", nullBitIndex_ ); |
| |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| |
| CDPT0( "VV0400: ", VV_BD, |
| "param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() )\n" ); |
| jit_value_t param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() ); |
| |
| // Are we getting the null bit? |
| if (nullBitIndex_ != -1) { |
| // For paranoia, make sure offset_ is not -1 also (indicating packed |
| // format against a varchar, which is not supported yet). |
| assert(offset_ != -1); |
| |
| //// jit_value_t mask = jit_value_create_nint_constant(f, jit_type_ubyte, |
| //// (UInt8)0x1 << (7 - (nullBitIndex_ & 7))); |
| |
| jit_value_t mask = ConstantInt::get( cfg->getInt8Ty(), |
| ((UInt8)0x1 << (7 - (nullBitIndex_ & 7)) ) ); |
| |
| //// jit_value_t nByte = jit_insn_load_relative(f, param, |
| //// offset_ + (nullBitIndex_ >> 3), jit_type_ubyte); |
| |
| jit_value_t nByte = cfg->IR_LoadRelativeWithType( Bldr, param, |
| offset_ + (nullBitIndex_ >> 3), |
| cfg->getInt8Ty() ); |
| |
| //// jitValue_ = jit_insn_and(f, nByte, mask); |
| |
| CDPT1( "VV0410: ", VV_BD, |
| "jitValue_ = Bldr->CreateAnd( nByte, mask = 0x%x )\n", (UInt8)0x1 << (7 - (nullBitIndex_ & 7)) ); |
| jitValue_ = Bldr->CreateAnd( nByte, mask ); |
| |
| // |
| // NOTE: There is an interesting point to make here. The CreateAnd() |
| // operation that we just did actually returned a pointer to an |
| // "AND" instruction whose first operand (nByte) is a pointer to a "load" |
| // instruction! See the discussion at the beginning of |
| // IR_LoadRelativeWithType about the fact that what we are really doing |
| // is teaching the IR generator HOW TO materialize values at runtime. |
| // It is for this reason that jitValue_ now points to an "AND" instruction |
| // whose first operand is a "load" instruction. |
| // |
| |
| CDPT2( "VV0412: ", VV_BD, "In getJitValue(): setting jitValue_ in PCodeOp at %p to %p\n", |
| this, jitValue_ ); |
| CDPT1( "VV0413: ", VV_BD, "CREATED Value's Type ID is %d\n", |
| (int) jitValue_->getType()->getTypeID() ); |
| } |
| else |
| { |
| //// jitValue_ = jit_insn_load_relative(f, param, offset_, type); |
| jitValue_ = cfg->IR_LoadRelativeWithType( Bldr, param, offset_, IRtype ); |
| |
| CDPT2( "VV0415: ", VV_BD, "In getJitValue(): setting jitValue_ in PCodeOp at " |
| "%p to %p\n", this, jitValue_ ); |
| CDPT1( "VV0417: ", VV_BD, "CREATED Value's Type ID is %d\n", |
| (int) jitValue_->getType()->getTypeID() ); |
| } |
| |
| } // End: else if (isVar()) |
| |
| |
| else { |
| // Accessing an undefined temp is not allowed. |
| // NOTE: An "undefined temp" is one which does not currently have a value. |
| // If it has not been given a value, then we should not be in this routine |
| // trying to get its value! |
| |
| CDPT0( "VV0420: ", VV_BD, |
| "ABOUT TO DO assert (FALSE) -- undefined temp is not allowed\n" ); |
| |
| assert (FALSE); |
| } |
| |
| CDPT2( "VV0421: ", VV_BD, "In getJitValue(): setting jitValueBlock_ = %p for PCop = %p\n", blk, this ); |
| |
| jitValueBlock_ = blk; |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) |
| { |
| jit_value_t tempVal = jitValue_; |
| jitValueBlock_ = NULL; |
| jitValuePtrBlock_ = NULL; |
| |
| CDPT1( "VV0VV0422: ", VV_BD, "In getJitValue(): NULLing jitValue_ in PCodeOp at " |
| "%p\n", this ); |
| |
| jitValue_ = jitValuePtr_ = NULL; |
| return tempVal; |
| } |
| |
| return jitValue_; |
| } |
| |
| // |
| // jitGenCompare() - generate a series of code to do a comparison |
| // between 2 values. Returns a "PHI Node". |
| // |
| jit_value_t PCodeCfg::jitGenCompare( IRBldr_t * Bldr |
| , enum cmpKind kindOfCompare |
| , jit_value_t oper1 |
| , jit_value_t oper2 |
| , jit_value_t trueRslt |
| , jit_value_t falseRslt |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| DPT0( "VV0500: ", VV_BD, "GOT into jitGenCompare()\n" ); |
| |
| llvm::LLVMContext &LLContxt = Bldr->getContext(); |
| |
| jit_value_t Zero = ConstantInt::get( oper1->getType(), 0 ); |
| jit_value_t IsZero = (Value *)NULL; |
| jit_value_t Rslt = (Value *)NULL; |
| |
| DPT2( "VV0502: ", VV_XD, "In jitGenCompare(): oper1 has TypeID = " |
| "%d, oper2 has %d\n", |
| oper1->getType()->getTypeID(), oper2->getType()->getTypeID() ); |
| |
| #if NExprDbgLvl >= VV_BD |
| if ( ( NExprDbgLvl_ >= VV_XD ) && |
| ( oper1->getType()->getTypeID() != oper2->getType()->getTypeID() ) ) |
| { |
| DPT2( "VV0504: ", VV_XD, "In jitGenCompare(): oper1 at %p, oper2 at %p\n", |
| oper1, oper2 ); |
| } |
| else if ( oper1->getType()->getTypeID() == Type::IntegerTyID ) |
| { |
| if ( oper1->getType()->getIntegerBitWidth() != |
| oper2->getType()->getIntegerBitWidth() ) |
| { |
| DPT2( "VV0506: ", VV_XD, |
| "In jitGenCompare(): oper1 width = %d, oper2 width = %d\n", |
| oper1->getType()->getIntegerBitWidth(), |
| oper2->getType()->getIntegerBitWidth() ); |
| DPT2( "VV0508: ", VV_XD, |
| "In jitGenCompare(): oper1 at %p, oper2 at %p\n", |
| oper1, oper2 ); |
| } |
| } |
| #endif |
| switch ( kindOfCompare ) |
| { |
| case IntCompare_EQ : |
| { |
| // NOTE: We use an XOR instruction here INSTEAD OF a ICmpEQ because |
| // LLVM's JIT Compiler for the x86 has a bug in it ... at least in |
| // Version 3.2 of LLVM. If we use a ICmpEQ and the operands are |
| // 32-bit operands, LLVM's JIT Compiler sometimes ends up producing |
| // a 64-bit comparison! |
| #if 0 |
| DPT0( "VV0510: ", VV_VD, |
| "IsZero = Bldr->CreateICmpEQ( oper1, oper2, 'ICmpEQ' )\n" ); |
| IsZero = Bldr->CreateICmpEQ( oper1, oper2, "ICmpEQ" ); |
| #else |
| DPT0( "VV0510: ", VV_VD, |
| "Rslt = Bldr->CreateXor( oper1, oper2, 'IXor' )\n" ); |
| Rslt = Bldr->CreateXor( oper1, oper2, "IXor" ); |
| |
| // NOTE: We must follow the XOR operation with a test for zero. |
| // You would think this unnecessary since the 'xor' machine |
| // instruction sets the Z flag in the x86's EFLAGS register. |
| // However, LLVM requires the CreateCondBr call (see |
| // the one below) to be done on a boolean variable and the |
| // result of the XOR is not a boolean, but multiple bits wide. |
| // NOTE: This does *not* result in two insructions in the |
| // final native code since LLVM's JIT Compiler is smart enough |
| // to optimize the unnecessary 'cmp' instruction away! |
| // |
| DPT0( "VV0511: ", VV_VD, |
| "IsZero = Bldr->CreateICmpEQ( Rslt, Zero, 'check0' )\n" ); |
| IsZero = Bldr->CreateICmpEQ( Rslt, Zero, "check0" ); |
| #endif |
| |
| break ; |
| } |
| case IntCompare_NE : |
| { |
| DPT0( "VV0520: ", VV_VD, |
| "IsZero = Bldr->CreateICmpNE( oper1, oper2, 'ICmpNE' )\n" ); |
| IsZero = Bldr->CreateICmpNE( oper1, oper2, "ICmpNE" ); |
| break ; |
| } |
| case IntCompare_SGT : |
| { |
| DPT0( "VV0523: ", VV_VD, |
| "IsZero = Bldr->CreateICmpSGT( oper1, oper2, 'ICmpSGT' )\n" ); |
| IsZero = Bldr->CreateICmpSGT( oper1, oper2, "ICmpSGT" ); |
| break ; |
| } |
| case IntCompare_UGT : |
| { |
| DPT0( "VV0525: ", VV_VD, |
| "IsZero = Bldr->CreateICmpUGT( oper1, oper2, 'ICmpUGT' )\n" ); |
| IsZero = Bldr->CreateICmpUGT( oper1, oper2, "ICmpUGT" ); |
| break ; |
| } |
| case IntCompare_UGE : |
| { |
| DPT0( "VV0526: ", VV_VD, |
| "IsZero = Bldr->CreateICmpUGE( oper1, oper2, 'ICmpUGE' )\n" ); |
| IsZero = Bldr->CreateICmpUGE( oper1, oper2, "ICmpUGE" ); |
| break ; |
| } |
| case IntCompare_SGE : |
| { |
| DPT0( "VV0527: ", VV_VD, |
| "IsZero = Bldr->CreateICmpSGE( oper1, oper2, 'ICmpSGE' )\n" ); |
| IsZero = Bldr->CreateICmpSGE( oper1, oper2, "ICmpSGE" ); |
| break ; |
| } |
| case IntCompare_SLT: |
| { |
| DPT0( "VV0528: ", VV_VD, |
| "IsZero = Bldr->CreateICmpSLT( oper1, oper2, 'ICmpSLT' )\n" ); |
| IsZero = Bldr->CreateICmpSLT( oper1, oper2, "ICmpSLT" ); |
| break ; |
| } |
| case IntCompare_SLE: |
| { |
| DPT0( "VV0529: ", VV_VD, |
| "IsZero = Bldr->CreateICmpSLE( oper1, oper2, 'ICmpSLE' )\n" ); |
| IsZero = Bldr->CreateICmpSLE( oper1, oper2, "ICmpSLE" ); |
| break ; |
| } |
| case IntCompare_ULT : |
| { |
| DPT0( "VV0530: ", VV_VD, |
| "IsZero = Bldr->CreateICmpULT( oper1, oper2, 'ICmpULT' )\n" ); |
| IsZero = Bldr->CreateICmpULT( oper1, oper2, "ICmpULT" ); |
| break ; |
| } |
| case IntCompare_ULE : |
| { |
| DPT0( "VV0531: ", VV_VD, |
| "IsZero = Bldr->CreateICmpULE( oper1, oper2, 'ICmpULE' )\n" ); |
| IsZero = Bldr->CreateICmpULE( oper1, oper2, "ICmpULE" ); |
| break ; |
| } |
| default : |
| assert(0==250) ; // ZZZZ FIX IF WE EVER GET HERE. |
| break ; |
| } |
| // Get ptr to current Function |
| llvm::Function *ExpFn = Bldr->GetInsertBlock()->getParent(); |
| |
| // Create 3 BasicBlock objects |
| // |
| // Note: We tell LLVM to give informative "names" to the blocks |
| // so we more easily recognize what we are seeing when we do an |
| // Intermediate Representation (IR) dump....used in debugging. |
| // |
| p_IR_block_t ThenBB = BasicBlock::Create( LLContxt, "CmpThenBlk" ); |
| p_IR_block_t ElseBB = BasicBlock::Create( LLContxt, "CmpElseBlk" ); |
| p_IR_block_t MergeBB = BasicBlock::Create( LLContxt, "CmpMergeBlk" ); |
| |
| DPT3( "VV0550: ", VV_VD, "ThenBB = %p, ElseBB = %p, MergeBB = %p\n", |
| ThenBB, ElseBB, MergeBB ); |
| DPT2( "VV0551: ", VV_VD, |
| "Bldr->CreateCondBr( IsZero, ThenBB = %p, ElseBB = %p )\n", ThenBB, ElseBB ); |
| Bldr->CreateCondBr( IsZero, ThenBB, ElseBB ); |
| |
| DPT1( "VV0552: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( ThenBB = %p )\n", ThenBB ); |
| ExpFn->getBasicBlockList().push_back( ThenBB ); |
| |
| DPT1( "VV0553: ", VV_VD, |
| "Bldr->SetInsertPoint( ThenBB = %p )\n", ThenBB ); |
| Bldr->SetInsertPoint( ThenBB ); |
| |
| jit_value_t ThenVal = trueRslt; |
| // NOTE: Since the "Then" Value was passed in, we don't need to generate |
| // any code here except for a Branch to the Merge Block. |
| |
| DPT1( "VV0555: ", VV_VD, |
| "Bldr->CreateBr( MergeBB = %p )\n", MergeBB ); |
| Bldr->CreateBr( MergeBB ); |
| |
| DPT1( "VV0556: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( ElseBB = %p )\n", ElseBB ); |
| ExpFn->getBasicBlockList().push_back( ElseBB ); |
| |
| DPT1( "VV0557: ", VV_VD, |
| "Bldr->SetInsertPoint( ElseBB = %p )\n", ElseBB ); |
| Bldr->SetInsertPoint( ElseBB ); |
| |
| jit_value_t ElseVal = falseRslt; |
| // NOTE: Since the "Else" Value was passed in, we don't need to generate |
| // any code here except for a Branch to the Merge Block. |
| |
| DPT1( "VV0560: ", VV_VD, |
| "Bldr->CreateBr( MergeBB = %p )\n", MergeBB ); |
| Bldr->CreateBr( MergeBB ); |
| |
| // Now set up to insert code into the "merge back" common place |
| DPT1( "VV0561: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( MergeBB = %p )\n", MergeBB ); |
| ExpFn->getBasicBlockList().push_back( MergeBB ); |
| |
| DPT1( "VV0562: ", VV_VD, |
| "Bldr->SetInsertPoint( MergeBB = %p )\n", MergeBB ); |
| Bldr->SetInsertPoint( MergeBB ); |
| |
| // |
| // Create PHI node. NOTE: Type of PHI node *must* match Type of Values passed to |
| // addIncoming(...) |
| // |
| DPT0( "VV0570: ", VV_VD, |
| "PN = Bldr->CreatePHI( trueRslt->getType(), 2, 'iftmp' )\n" ); |
| PHINode *PN = Bldr->CreatePHI( trueRslt->getType(), |
| 2, "iftmp" ); // '2' is LLVM version # !! |
| DPT2( "VV0571: ", VV_VD, |
| "PN->addIncoming( ThenVal at %p, from IR blk at %p )\n", ThenVal, ThenBB ); |
| PN->addIncoming( ThenVal, ThenBB ); |
| |
| DPT2( "VV0572: ", VV_VD, |
| "PN->addIncoming( ElseVal at %p, from IR blk at %p )\n", ElseVal, ElseBB ); |
| PN->addIncoming( ElseVal, ElseBB ); |
| return (PN); |
| } |
| |
| // |
| // getJitType() - return an LLVM type corresponding to the specified |
| // operand type. |
| // |
| jit_type_t PCodeOperand::getJitType( PCodeCfg * cfg , PCIT::AddressingMode oprTyp ) |
| { |
| PCIT::AddressingMode OperTyp = operandType_ ; |
| |
| if ( oprTyp != PCIT::AM_NONE ) |
| OperTyp = oprTyp ; |
| |
| switch ( OperTyp ) { |
| case PCIT::MBIN8: return cfg->getInt8Ty() ; |
| case PCIT::MBIN16U: return cfg->getInt16Ty() ; |
| case PCIT::MBIN16S: return cfg->getInt16Ty() ; |
| case PCIT::MBIN32U: return cfg->getInt32Ty() ; |
| case PCIT::MBIN32S: return cfg->getInt32Ty() ; |
| case PCIT::MBIN64S: return cfg->getInt64Ty() ; |
| case PCIT::MASCII: |
| case PCIT::MATTR5: |
| case PCIT::MBIGS: |
| return cfg->getInt1PtrTy() ; // Use instead of LIBJIT's void ptr type |
| case PCIT::MPTR32: |
| { |
| if ( forAlignedFormat() ) |
| return cfg->getInt8Ty() ; // Return a single byte |
| else |
| return cfg->getInt1PtrTy() ; // Use instead of LIBJIT's void ptr type |
| } |
| case PCIT::MFLT64: |
| return cfg->getFloatPtrTy() ; |
| } |
| |
| // No other types supported |
| assert(FALSE); |
| |
| return cfg->getInt1PtrTy() ; // Should not get here. |
| } |
| |
| // |
| // genMemCopyLoop() - generate code to do a memory-to-memory copy. |
| // |
| void PCodeCfg::genMemCopyLoop( IRBldr_t * Bldr |
| , jit_value_t srcPtr |
| , jit_value_t tgtPtr |
| , jit_value_t maxLen |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| jit_value_t BytesPer, CmpRslt ; |
| jit_value_t RndMaxLen, ByteCtVal ; |
| jit_value_t MaxLen64 ; |
| DPT0( "VV0600: ", VV_BD, "GOT into genMemCopyLoop()\n" ); |
| |
| jit_value_t Zero = ConstantInt::get( int64Ty_, 0 ); |
| |
| llvm::LLVMContext &LLContxt = Bldr->getContext(); |
| llvm::Function *ExpFn = Bldr->GetInsertBlock()->getParent(); |
| |
| p_IR_block_t fastLoopLabel = BasicBlock::Create( LLContxt, "MemCpyFastBlk" ); |
| p_IR_block_t endLabel = BasicBlock::Create( LLContxt, "MemCpyEndBlk" ); |
| |
| DPT2( "VV0602: ", VV_VD, "fastLoopLabel = %p, endLabel = %p\n", |
| fastLoopLabel, endLabel ); |
| |
| Int32 bytesAtOnce = 8; |
| |
| BytesPer = ConstantInt::get( int64Ty_, bytesAtOnce ); |
| DPT0( "VV0605: ", VV_VD, |
| "MaxLen64 = Bldr->CreateZExt( maxLen, int64Ty_, 'ExtMaxLen')\n" ); |
| MaxLen64 = Bldr->CreateZExt( maxLen, int64Ty_, "ExtMaxLen"); |
| |
| DPT0( "VV0606: ", VV_VD, |
| "RndMaxLen = Bldr->CreateUDiv( MaxLen64, BytesPer, 'UDiv' )\n" ); |
| RndMaxLen = Bldr->CreateUDiv( MaxLen64, BytesPer, "UDiv" ); |
| |
| DPT0( "VV0607: ", VV_VD, |
| "RndMaxLen = Bldr->CreateMul( RndMaxLen, BytesPer, 'Mul' )\n" ); |
| RndMaxLen = Bldr->CreateMul( RndMaxLen, BytesPer, "Mul" ); |
| |
| DPT0( "VV0610: ", VV_VD, |
| "AllocaInst * ByteCt = Bldr->CreateAlloca( int64Ty_ )\n" ); |
| AllocaInst * ByteCt = Bldr->CreateAlloca( int64Ty_ ); |
| |
| DPT0( "VV0611: ", VV_VD, |
| "Bldr->CreateStore( Zero, ByteCt )\n" ); |
| Bldr->CreateStore( Zero, ByteCt ); |
| |
| DPT0( "VV0612: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpULT( RndMaxLen, BytesPer, 'ICmp.RndMaxLen' )\n" ); |
| CmpRslt = Bldr->CreateICmpULT( RndMaxLen, BytesPer, "ICmp.RndMaxLen" ); |
| |
| DPT0( "VV0613: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, endLabel, fastLoopLabel )\n" ); |
| Bldr->CreateCondBr( CmpRslt, endLabel, fastLoopLabel ); |
| |
| // Start fast loop here |
| |
| DPT1( "VV0615: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( fastLoopLabel = %p )\n" , fastLoopLabel); |
| ExpFn->getBasicBlockList().push_back( fastLoopLabel ); |
| |
| DPT0( "VV0616: ", VV_VD, |
| "Bldr->SetInsertPoint( fastLoopLabel )\n" ); |
| Bldr->SetInsertPoint( fastLoopLabel ); |
| |
| // Copy multiple bytes at a time. |
| DPT0( "VV0617: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); // Re-load within loop |
| |
| DPT0( "VV0618: ", VV_VD, |
| "ThisSrc = Bldr->CreateGEP( srcPtr, ByteCtVal, 'ThisSrc' )\n" ); |
| jit_value_t ThisSrc = Bldr->CreateGEP( srcPtr, ByteCtVal, "ThisSrc" ); |
| |
| DPT0( "VV0619: ", VV_VD, |
| "ThisTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, 'ThisTgt' )\n" ); |
| jit_value_t ThisTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, "ThisTgt" ); |
| |
| jit_value_t MultiBytes = IR_LoadRelativeWithType( Bldr, ThisSrc, |
| 0, int64Ty_ ); |
| IR_StoreRelativeWithType( Bldr, MultiBytes, ThisTgt, |
| 0, int64Ty_ ); |
| |
| // Increment count of bytes copyied |
| DPT0( "VV0621: ", VV_VD, |
| "ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, 'nextIncr')\n"); |
| ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, "nextIncr" ); |
| |
| DPT0( "VV0622: ", VV_VD, |
| "Bldr->CreateStore( ByteCtVal, ByteCt, 'storeByteCt' )\n" ); |
| Bldr->CreateStore( ByteCtVal, ByteCt, "storeByteCt" ); |
| |
| |
| // while (ByteCtVal < RndMaxLen) branch to fastLoop |
| DPT0( "VV0623: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpULT( ByteCtVal, RndMaxLen, 'ICmp.ByteCt' )\n" ); |
| CmpRslt = Bldr->CreateICmpULT( ByteCtVal, RndMaxLen, "ICmp.ByteCt" ); |
| |
| DPT0( "VV0624: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, fastLoopLabel, endLabel )\n" ); |
| Bldr->CreateCondBr( CmpRslt, fastLoopLabel, endLabel ); |
| |
| DPT1( "VV0625: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( endLabel = %p )\n", endLabel ); |
| ExpFn->getBasicBlockList().push_back( endLabel ); |
| |
| DPT0( "VV0626: ", VV_VD, |
| "Bldr->SetInsertPoint( endLabel )\n" ); |
| Bldr->SetInsertPoint( endLabel ); |
| |
| // Now copy any remaining bytes (from 0 to 7 bytes possible) |
| |
| p_IR_block_t slowLoopLabel = BasicBlock::Create( LLContxt, "MemCpySlowBlk" ); |
| p_IR_block_t end2Label = BasicBlock::Create( LLContxt, "MemCpyEndBlk" ); |
| |
| DPT2( "VV0628: ", VV_VD, "slowLoopLabel = %p, end2Label = %p\n", |
| slowLoopLabel, end2Label ); |
| |
| bytesAtOnce = 1; |
| |
| BytesPer = ConstantInt::get( int64Ty_, bytesAtOnce ); |
| |
| DPT0( "VV0630: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); |
| |
| DPT0( "VV0632: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpUGE( ByteCtVal, MaxLen64, 'ICmp.RndMaxLen' )\n" ); |
| CmpRslt = Bldr->CreateICmpUGE( ByteCtVal, MaxLen64, "ICmp.RndMaxLen" ); |
| |
| DPT0( "VV0633: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, end2Label, slowLoopLabel )\n" ); |
| Bldr->CreateCondBr( CmpRslt, end2Label, slowLoopLabel ); |
| |
| // Start slow loop here |
| |
| DPT1( "VV0635: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( slowLoopLabel = %p )\n", slowLoopLabel ); |
| ExpFn->getBasicBlockList().push_back( slowLoopLabel ); |
| |
| DPT0( "VV0636: ", VV_VD, |
| "Bldr->SetInsertPoint( slowLoopLabel )\n" ); |
| Bldr->SetInsertPoint( slowLoopLabel ); |
| |
| // Copy multiple bytes at a time. |
| DPT0( "VV0637: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); // Re-load within the loop |
| |
| DPT0( "VV0638: ", VV_VD, |
| "CurrSrc = Bldr->CreateGEP( srcPtr, ByteCtVal, 'CurrSrc' )\n" ); |
| jit_value_t CurrSrc = Bldr->CreateGEP( srcPtr, ByteCtVal, "CurrSrc" ); |
| |
| DPT0( "VV0639: ", VV_VD, |
| "CurrTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, 'CurrTgt' )\n" ); |
| jit_value_t CurrTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, "CurrTgt" ); |
| |
| jit_value_t OneByte = IR_LoadRelativeWithType( Bldr, CurrSrc, |
| 0, int8Ty_ ); |
| IR_StoreRelativeWithType( Bldr, OneByte, CurrTgt, |
| 0, int8Ty_ ); |
| |
| // Increment loop count |
| DPT0( "VV0641: ", VV_VD, |
| "ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, 'nextIncr')\n"); |
| ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, "nextIncr" ); |
| |
| DPT0( "VV0642: ", VV_VD, |
| "Bldr->CreateStore( ByteCtVal, ByteCt, 'storeByteCt' )\n" ); |
| Bldr->CreateStore( ByteCtVal, ByteCt, "storeByteCt" ); |
| |
| |
| // while (ByteCtVal < MaxLen64) branch to slowLoop |
| DPT0( "VV0643: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpULT( ByteCtVal, MaxLen64, 'ICmp.ByteCt' )\n" ); |
| CmpRslt = Bldr->CreateICmpULT( ByteCtVal, MaxLen64, "ICmp.ByteCt" ); |
| |
| DPT0( "VV0644: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, slowLoopLabel, end2Label )\n" ); |
| Bldr->CreateCondBr( CmpRslt, slowLoopLabel, end2Label ); |
| |
| DPT1( "VV0645: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( end2Label = %p )\n", end2Label ); |
| ExpFn->getBasicBlockList().push_back( end2Label ); |
| |
| DPT0( "VV0646: ", VV_VD, |
| "Bldr->SetInsertPoint( end2Label )\n" ); |
| Bldr->SetInsertPoint( end2Label ); |
| } |
| |
| // |
| // genMemCmpLoop() - generate code to do a memory-to-memory compare. |
| // |
| jit_value_t PCodeCfg::genMemCmpLoop( IRBldr_t * Bldr |
| , enum cmpKind KindOfCmp |
| , jit_value_t src1Ptr |
| , jit_value_t src2Ptr |
| , jit_value_t maxLen |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| jit_value_t BytesPer, Is_LT ; |
| jit_value_t RndMaxLen, ByteCtVal ; |
| jit_value_t MaxLen64 ; |
| jit_value_t IsZero ; |
| jit_value_t IsEqual ; |
| DPT0( "VVa600: ", VV_BD, "GOT into genMemCmpLoop()\n" ); |
| |
| jit_value_t Zero = ConstantInt::get( int64Ty_, 0 ); |
| |
| llvm::LLVMContext &LLContxt = Bldr->getContext(); |
| llvm::Function *ExpFn = Bldr->GetInsertBlock()->getParent(); |
| |
| p_IR_block_t fastCmpLpLabel = BasicBlock::Create( LLContxt, "MemCmpFastBlk" ); |
| p_IR_block_t fastCmpNxtLabel = BasicBlock::Create( LLContxt, "MemCmpFastNextBlk" ); |
| p_IR_block_t slowCmpLpLabel = BasicBlock::Create( LLContxt, "MemCmpSlwBlk" ); |
| p_IR_block_t slowContLabel = BasicBlock::Create( LLContxt, "MemCmpSlwContBlk" ); |
| p_IR_block_t slowCmpEndLabel = BasicBlock::Create( LLContxt, "MemCmpSlwEndBlk" ); |
| |
| DPT2( "VVa602: ", VV_VD, "fastCmpLpLabel = %p, fastCmpNxtLabel = %p\n", |
| fastCmpLpLabel, fastCmpNxtLabel ); |
| DPT2( "VVa602: ", VV_VD, "slowCmpLpLabel = %p, slowContLabel = %p\n" , |
| slowCmpLpLabel, slowContLabel ); |
| DPT1( "VVa602: ", VV_VD, "slowCmpEndLabel = %p\n", |
| slowCmpEndLabel ); |
| Int32 bytesAtOnce = 8; |
| |
| BytesPer = ConstantInt::get( int64Ty_, bytesAtOnce ); |
| DPT0( "VVa605: ", VV_VD, |
| "MaxLen64 = Bldr->CreateZExt( maxLen, int64Ty_, 'ExtMaxLen')\n" ); |
| MaxLen64 = Bldr->CreateZExt( maxLen, int64Ty_, "ExtMaxLen"); |
| |
| // NOTE: We subtract 1 so that we ensure we always go through the slow loop |
| // and do the caller-specified comparison for at least one byte. |
| |
| jit_value_t One = ConstantInt::get( int64Ty_, 1 ); |
| |
| DPT0( "VVa606: ", VV_VD, |
| "RndMaxLen = Bldr->CreateSub( MaxLen64, One, 'Sub1' )\n" ); |
| RndMaxLen = Bldr->CreateSub( MaxLen64, One, "Sub1" ); |
| |
| DPT0( "VVa607: ", VV_VD, |
| "RndMaxLen = Bldr->CreateUDiv( RndMaxLen, BytesPer, 'UDiv' )\n" ); |
| RndMaxLen = Bldr->CreateUDiv( RndMaxLen, BytesPer, "UDiv" ); |
| |
| DPT0( "VVa608: ", VV_VD, |
| "RndMaxLen = Bldr->CreateMul( RndMaxLen, BytesPer, 'Mul' )\n" ); |
| RndMaxLen = Bldr->CreateMul( RndMaxLen, BytesPer, "Mul" ); |
| |
| DPT0( "VVa610: ", VV_VD, |
| "AllocaInst * ByteCt = Bldr->CreateAlloca( int64Ty_ )\n" ); |
| AllocaInst * ByteCt = Bldr->CreateAlloca( int64Ty_ ); |
| |
| DPT0( "VVa611: ", VV_VD, |
| "Bldr->CreateStore( Zero, ByteCt )\n" ); |
| Bldr->CreateStore( Zero, ByteCt ); |
| |
| // |
| // NOTE: If we don't have at least BytesPer bytes to compare, then |
| // we go directly to the slow loop. |
| // |
| DPT0( "VVa612: ", VV_VD, |
| "Is_LT = Bldr->CreateICmpSLT( RndMaxLen, BytesPer, 'ICmp.RndMaxLen' )\n" ); |
| Is_LT = Bldr->CreateICmpSLT( RndMaxLen, BytesPer, "ICmp.RndMaxLen" ); |
| |
| DPT0( "VVa613: ", VV_VD, |
| "Bldr->CreateCondBr( Is_LT, slowCmpLpLabel, fastCmpLpLabel )\n" ); |
| Bldr->CreateCondBr( Is_LT, slowCmpLpLabel, fastCmpLpLabel ); |
| |
| // Start fast loop here |
| |
| DPT1( "VVa615: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( fastCmpLpLabel = %p )\n" , fastCmpLpLabel); |
| ExpFn->getBasicBlockList().push_back( fastCmpLpLabel ); |
| |
| DPT1( "VVa616: ", VV_VD, |
| "Bldr->SetInsertPoint( fastCmpLpLabel = %p )\n", fastCmpLpLabel ); |
| Bldr->SetInsertPoint( fastCmpLpLabel ); |
| |
| // Copy multiple bytes at a time. |
| DPT0( "VVa617: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); // Re-load within loop |
| |
| DPT0( "VVa618: ", VV_VD, |
| "ThisSrc1 = Bldr->CreateGEP( src1Ptr, ByteCtVal, 'ThisSrc1' )\n" ); |
| jit_value_t ThisSrc1 = Bldr->CreateGEP( src1Ptr, ByteCtVal, "ThisSrc1" ); |
| |
| DPT0( "VVa619: ", VV_VD, |
| "ThisSrc2 = Bldr->CreateGEP( src2Ptr, ByteCtVal, 'ThisSrc2' )\n" ); |
| jit_value_t ThisSrc2 = Bldr->CreateGEP( src2Ptr, ByteCtVal, "ThisSrc2" ); |
| |
| jit_value_t MultiBytes1 = IR_LoadRelativeWithType( Bldr, ThisSrc1, |
| 0, int64Ty_ ); |
| jit_value_t MultiBytes2 = IR_LoadRelativeWithType( Bldr, ThisSrc2, |
| 0, int64Ty_ ); |
| // NOTE: Always compare for EQ in the fast loop. |
| // The slow loop will do the real comparison -- once we find a difference |
| DPT0( "VVa619a: ", VV_VD, |
| "IsZero = Bldr->CreateICmpEQ( MultiBytes1, MultiBytes2, 'cmp8Bytes' )\n" ); |
| IsZero = Bldr->CreateICmpEQ( MultiBytes1, MultiBytes2, "cmp8Bytes" ); |
| |
| DPT2( "VVa620: ", VV_VD, |
| "Bldr->CreateCondBr( IsZero, fastCmpNxtLabel = %p, slowCmpLpLabel = %p )\n", |
| fastCmpNxtLabel, slowCmpLpLabel ); |
| Bldr->CreateCondBr( IsZero, fastCmpNxtLabel, slowCmpLpLabel ); |
| |
| DPT1( "VVa620a: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( fastCmpNxtLabel = %p )\n" , fastCmpNxtLabel ); |
| ExpFn->getBasicBlockList().push_back( fastCmpNxtLabel ); |
| |
| DPT1( "VVa620b: ", VV_VD, |
| "Bldr->SetInsertPoint( fastCmpNxtLabel = %p )\n", fastCmpNxtLabel ); |
| Bldr->SetInsertPoint( fastCmpNxtLabel ); |
| |
| // Increment count of bytes copied |
| DPT0( "VVa621: ", VV_VD, |
| "ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, 'nextIncr')\n"); |
| ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, "nextIncr" ); |
| |
| DPT0( "VVa622: ", VV_VD, |
| "Bldr->CreateStore( ByteCtVal, ByteCt, 'storeByteCt' )\n" ); |
| Bldr->CreateStore( ByteCtVal, ByteCt, "storeByteCt" ); |
| |
| |
| // while (ByteCtVal < RndMaxLen) branch to fastLoop |
| DPT0( "VVa623: ", VV_VD, |
| "Is_LT = Bldr->CreateICmpULT( ByteCtVal, RndMaxLen, 'ICmp.ByteCt' )\n" ); |
| Is_LT = Bldr->CreateICmpULT( ByteCtVal, RndMaxLen, "ICmp.ByteCt" ); |
| |
| DPT0( "VVa624: ", VV_VD, |
| "Bldr->CreateCondBr( Is_LT, fastCmpLpLabel, slowCmpLpLabel )\n" ); |
| Bldr->CreateCondBr( Is_LT, fastCmpLpLabel, slowCmpLpLabel ); |
| |
| // Now compare any remaining bytes (from 1 to 8 bytes possible) |
| |
| // NOTE: Because we subtracted 1 from RndMaxLen (above), we are |
| // guaranteed that ByteCt < MaxLen64 so we are guaranteed that |
| // we *must* go through the slow loop at least once. |
| |
| // Start slow loop here |
| |
| DPT1( "VVa635: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( slowCmpLpLabel = %p )\n", slowCmpLpLabel ); |
| ExpFn->getBasicBlockList().push_back( slowCmpLpLabel ); |
| |
| DPT1( "VVa636: ", VV_VD, |
| "Bldr->SetInsertPoint( slowCmpLpLabel = %p )\n", slowCmpLpLabel ); |
| Bldr->SetInsertPoint( slowCmpLpLabel ); |
| |
| bytesAtOnce = 1; |
| |
| BytesPer = ConstantInt::get( int64Ty_, bytesAtOnce ); |
| |
| // Copy one byte at a time. |
| DPT0( "VVa637: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); // Re-load within the loop |
| |
| DPT0( "VVa638: ", VV_VD, |
| "CurrSrc1 = Bldr->CreateGEP( src1Ptr, ByteCtVal, 'CurrSrc1' )\n" ); |
| jit_value_t CurrSrc1 = Bldr->CreateGEP( src1Ptr, ByteCtVal, "CurrSrc1" ); |
| |
| DPT0( "VVa639: ", VV_VD, |
| "CurrSrc2 = Bldr->CreateGEP( src2Ptr, ByteCtVal, 'CurrSrc2' )\n" ); |
| jit_value_t CurrSrc2 = Bldr->CreateGEP( src2Ptr, ByteCtVal, "CurrSrc2" ); |
| |
| jit_value_t OneByte1 = IR_LoadRelativeWithType( Bldr, CurrSrc1, |
| 0, int8Ty_ ); |
| jit_value_t OneByte2 = IR_LoadRelativeWithType( Bldr, CurrSrc2, |
| 0, int8Ty_ ); |
| switch ( KindOfCmp ) |
| { |
| default: |
| case ByteCompare_EQ: |
| DPT0( "VVa640eq: ", VV_VD, |
| "IsZero = Bldr->CreateICmpEQ( OneByte1, OneByte2, 'cmp1ByteEQ' )\n" ); |
| IsZero = Bldr->CreateICmpEQ( OneByte1, OneByte2, "cmp1ByteEQ" ); |
| break; |
| case ByteCompare_NE: |
| DPT0( "VVa640ne: ", VV_VD, |
| "IsZero = Bldr->CreateICmpNE( OneByte1, OneByte2, 'cmp1ByteNE' )\n" ); |
| IsZero = Bldr->CreateICmpNE( OneByte1, OneByte2, "cmp1ByteNE" ); |
| break; |
| case ByteCompare_LT: |
| DPT0( "VVa640ult: ", VV_VD, |
| "IsZero = Bldr->CreateICmpULT( OneByte1, OneByte2, 'cmp1ByteLT' )\n" ); |
| IsZero = Bldr->CreateICmpULT( OneByte1, OneByte2, "cmp1ByteLT" ); |
| break; |
| case ByteCompare_LE: |
| DPT0( "VVa640ule: ", VV_VD, |
| "IsZero = Bldr->CreateICmpULE( OneByte1, OneByte2, 'cmp1ByteLE' )\n" ); |
| IsZero = Bldr->CreateICmpULE( OneByte1, OneByte2, "cmp1ByteLE" ); |
| break; |
| case ByteCompare_GT: |
| DPT0( "VVa640ugt: ", VV_VD, |
| "IsZero = Bldr->CreateICmpUGT( OneByte1, OneByte2, 'cmp1ByteGT' )\n" ); |
| IsZero = Bldr->CreateICmpUGT( OneByte1, OneByte2, "cmp1ByteGT" ); |
| break; |
| case ByteCompare_GE: |
| DPT0( "VVa640uge: ", VV_VD, |
| "IsZero = Bldr->CreateICmpUGE( OneByte1, OneByte2, 'cmp1ByteGE' )\n" ); |
| IsZero = Bldr->CreateICmpUGE( OneByte1, OneByte2, "cmp1ByteGE" ); |
| break; |
| } |
| |
| DPT0( "VVa641: ", VV_VD, |
| "IsEqual = Bldr->CreateICmpEQ( OneByte1, OneByte2, 'cmp1ByteEQ' )" ); |
| IsEqual = Bldr->CreateICmpEQ( OneByte1, OneByte2, "cmp1ByteEQ" ); |
| |
| DPT2( "VVa642: ", VV_VD, |
| "Bldr->CreateCondBr( IsEqual, slowContLabel = %p, slowCmpEndLabel = %p )\n", |
| slowContLabel, slowCmpEndLabel ); |
| Bldr->CreateCondBr( IsEqual, slowContLabel, slowCmpEndLabel ); |
| |
| DPT1( "VVa642a: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( slowContLabel = %p )\n" , slowContLabel ); |
| ExpFn->getBasicBlockList().push_back( slowContLabel ); |
| |
| DPT1( "VVa642b: ", VV_VD, |
| "Bldr->SetInsertPoint( slowContLabel = %p )\n", slowContLabel ); |
| Bldr->SetInsertPoint( slowContLabel ); |
| |
| // Increment loop count |
| DPT0( "VVa643: ", VV_VD, |
| "ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, 'nextIncr')\n"); |
| ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, "nextIncr" ); |
| |
| DPT0( "VVa644: ", VV_VD, |
| "Bldr->CreateStore( ByteCtVal, ByteCt, 'storeByteCt' )\n" ); |
| Bldr->CreateStore( ByteCtVal, ByteCt, "storeByteCt" ); |
| |
| |
| // while (ByteCtVal < MaxLen64) branch to slowLoop |
| DPT0( "VVa645: ", VV_VD, |
| "Is_LT = Bldr->CreateICmpULT( ByteCtVal, MaxLen64, 'ICmp.ByteCt' )\n" ); |
| Is_LT = Bldr->CreateICmpULT( ByteCtVal, MaxLen64, "ICmp.ByteCt" ); |
| |
| DPT0( "VVa646: ", VV_VD, |
| "Bldr->CreateCondBr( Is_LT, slowCmpLpLabel, slowCmpEndLabel )\n" ); |
| Bldr->CreateCondBr( Is_LT, slowCmpLpLabel, slowCmpEndLabel ); |
| |
| DPT1( "VVa647: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( slowCmpEndLabel = %p )\n", slowCmpEndLabel ); |
| ExpFn->getBasicBlockList().push_back( slowCmpEndLabel ); |
| |
| DPT1( "VVa648: ", VV_VD, |
| "Bldr->SetInsertPoint( slowCmpEndLabel = %p )\n", slowCmpEndLabel ); |
| Bldr->SetInsertPoint( slowCmpEndLabel ); |
| |
| return ( IsZero ); |
| } |
| |
| // |
| // allocJitValue() - tell LLVM to allocate a location (on the stack) |
| // to hold a temporary value. NOTE: Most of these are allocated |
| // just *before* we start generating native code for PCODE instructions. |
| // By doing it early, we ensure that all paths through the PCODE |
| // instructions will use the same allocation location for the |
| // specified operand. |
| // |
| void PCodeOperand::allocJitValue( PCodeCfg * cfg |
| , IRBldr_t * Bldr |
| , PCIT::AddressingMode OprTyp |
| , Int32 Len |
| , Int32 Num |
| ) |
| { |
| #if NExprDbgLvl >= VV_NO |
| char NExBuf[500]; |
| #endif |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| |
| CDPT2( "VV0647: ", VV_BD, "In allocJitValue(): operand=%p, this=%p\n", |
| operand, this ); |
| if (operand != this) |
| return operand->allocJitValue( cfg, Bldr, OprTyp, Len, Num ); |
| |
| if ( jitValue_ ) return; // Already allocated |
| |
| jit_type_t IRtype = getJitType( cfg, OprTyp ); |
| if ( IRtype == cfg->getInt1PtrTy() ) |
| { |
| if ( Len = 2 ) IRtype = cfg->getInt16PtrTy() ; |
| if ( Len = 4 ) IRtype = cfg->getInt32PtrTy() ; |
| if ( Len = 8 ) IRtype = cfg->getInt64PtrTy() ; |
| } |
| CDPT2( "VV0647a: ", VV_BD, "In allocJitValue(): Len = %d, IRtype = %p\n", |
| Len, IRtype ); |
| |
| jit_value_t NumV = ConstantInt::get( cfg->getInt32Ty() , Num ); |
| |
| CDPT3( "VV0648: ", VV_BD, |
| "jitValue_ = (llvm::Value *)Bldr->CreateAlloca( IRtype = %p, NumV = %d )" |
| " for PCOp = %p\n", IRtype, Num, this ); |
| jitValue_ = (llvm::Value *)Bldr->CreateAlloca( IRtype , NumV ); |
| |
| CDPT1( "VV0649: ", VV_BD, "Just set jitValue_ = %p (ptr to AllocaInst)\n", |
| jitValue_ ); |
| } |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| |
| // FIX: Overlapped types can have problems too |
| jit_value_t PCodeOperand::getJitValue(PCodeCfg* cfg, |
| jit_function_t f, |
| jit_type_t type, |
| PCodeBlock* b, |
| PCodeOperand* orig = NULL, |
| NABoolean noSave = FALSE) |
| { |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| if (operand != this) |
| return operand->getJitValue(cfg, f, type, b, this, noSave); |
| |
| // Make sure we properly indicate this this object *is* the original one. |
| if (orig == NULL) |
| orig = this; |
| |
| // |
| // Get pointer to operand, if that's what is needed |
| // |
| |
| if (type == jit_type_void_ptr) { |
| |
| // If already defined somewhere, perhaps it can be reused? |
| if (jitValuePtr_) { |
| assert(jitValueBlock_ != NULL); |
| if (b->onesVector.testBit(jitValueBlock_->getBlockNum())) |
| return jitValuePtr_; |
| else |
| jitValuePtr_ = NULL; |
| } |
| |
| // Non-native temps will be accessed directly from the passed in temps |
| // area. If that temp was previously defined as a jit value (e.g. size of |
| // temp fit native storage container), then we skip to the else clause so |
| // the address is simply taken for the jit value. |
| if (isVar() || isConst() || (!jitValue_ && orig->isNonNativeTemp())) { |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| |
| // For varchars we return a pointer to the start of length indicator. |
| if (getType() == PCIT::MATTR5) { |
| // If we're not dealing with a varchar, or if it is the first varchar, |
| // we don't need to go through the VOA offset. |
| if (!isVarchar() || (getVoaOffset() == -1)) { |
| jitValuePtr_ = |
| jit_insn_add_relative(f, param, (offset_ - vcIndicatorLen_)); |
| } |
| else |
| { |
| jit_type_t t = ((vcIndicatorLen_ == 2) |
| ? jit_type_ushort : jit_type_uint); |
| |
| jit_value_t v = jit_insn_load_relative(f, param, voaOffset_, t); |
| |
| jitValuePtr_ = jit_insn_add(f, param, v); |
| |
| // Now set up pointer, moving past null indicator if required. |
| if (vcNullIndicatorLen_) |
| jitValuePtr_ = jit_insn_add_relative(f, jitValuePtr_, |
| vcNullIndicatorLen_); |
| } |
| } |
| else |
| jitValuePtr_ = jit_insn_add_relative(f, param, offset_); |
| } |
| else { |
| // Normally we would force the jitValue_ to be defined if we're attempting |
| // to get it. However, in some cases (like FILL_MEM_BYTES) we make a |
| // a call to get it first so that things like the vc length can be written |
| // to it first. |
| // FIX: fix this so that we can continue to assert that jitValue_ should |
| // be defined first. Fixing it involves having storeJitValue support |
| // all possible stores (vc lengths, actual values, etc.). |
| |
| // Must be called and it must already be defined |
| |
| if (!jitValue_) { |
| // We reached a situation that we can't support. For example, we could |
| // having something like this: |
| // |
| // B1: [2,0] = ... |
| // Branch B3 |
| // B2: [2,0] = ... |
| // B3: = [2,0] |
| // |
| // If we allocated space for [2,0] in B1, and then do the same in B2, |
| // which one do we use for B3? Also, if we try to allocate space for |
| // [2,0] in B3, then it would be completely wrong. |
| |
| cfg->setJitFailureSeen(); |
| |
| // And for the sake of nothing else failing along the way, create a |
| // bogus value to return. |
| return jit_value_create(f, jit_type_int); |
| } |
| |
| assert (jitValue_ && isTemp()); |
| |
| // Temporary value needs to be addressable. |
| jit_value_set_addressable(jitValue_); |
| |
| // Return the address of this temp variable. |
| jitValuePtr_ = jit_insn_address_of(f, jitValue_); |
| |
| // If the jitValue_ was not defined in this current block, then the safe |
| // thing to do is simply return the address of jitValue, but *do not* |
| // save the pointer in jitValuePtr_, since that will lead to confusion |
| // on what was defined where. |
| if (jitValueBlock_ != b) { |
| jit_value_t temp = jitValuePtr_; |
| jitValuePtr_ = NULL; |
| return temp; |
| } |
| } |
| |
| jitValueBlock_ = b; |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) { |
| jit_value_t tempVal = jitValuePtr_; |
| jitValueBlock_ = NULL; |
| jitValue_ = jitValuePtr_ = NULL; |
| return tempVal; |
| } |
| |
| return jitValuePtr_; |
| } |
| |
| // |
| // Get value of operand |
| // |
| |
| // If already defined somewhere, perhaps it can be reused? If it's a temp, |
| // however, then the assumption is that all uses have a def which reach it, |
| // and that def is available in jitValue_. |
| if (jitValue_) { |
| assert(jitValueBlock_ != NULL); |
| if (isTemp() || b->onesVector.testBit(jitValueBlock_->getBlockNum())) |
| { |
| // It's possible that we have some overlapping operands. The following |
| // deals with it (or at least for the majority of the cases where we see |
| // an overlap :() |
| jit_type_t jitValType = jit_value_get_type(jitValue_); |
| if (jit_type_get_size(jitValType) > jit_type_get_size(type)) |
| return jit_insn_convert(f, jitValue_, type, 0); |
| |
| return jitValue_; |
| } |
| |
| jitValue_ = NULL; |
| } |
| |
| if (isConst()) { |
| // |
| // FIX: the assumption right now is that only integers are considered for |
| // native expressions. That will change shortly. In the meantime, however, |
| // this implies that getIntConstValue() should be called on the operand to |
| // retrieve the constant value. |
| // |
| // FIX: getIntConstValue() should probably be "relaxed" a little so as to |
| // support MPTR32 and MFLT (both of which may be casted into integer types |
| // during same-sized moves). For now, work around by adding logic here. |
| // |
| |
| if (type == jit_type_long) { |
| // MFLT64 can sometimes be the original type of the operand being sought |
| // after (e.g. PCIT::MFLT64_MFLT64 --> PCIT::MBIN64S_MBIN64S). Use the |
| // original operand to get the constant value. |
| |
| PCodeOperand* op = ((getType() == PCIT::MFLT64) || |
| (getType() == PCIT::MFLT32)) |
| ? orig : this; |
| |
| Int64 val = cfg->getIntConstValue(op); |
| |
| jitValue_ = jit_value_create_long_constant(f, type, val); |
| } |
| else if (getType() == PCIT::MPTR32) { |
| // MPTR32 can sometimes be the original type of the operand being sought |
| // after (e.g. PCIT::MBIN8_MBIN8_IBIN32S --> PCIT::MBIN8_MBIN8). Use the |
| // original operand to get the constant value. |
| |
| Int32 val = (Int32)cfg->getIntConstValue(((orig) ? orig : this)); |
| jitValue_ = jit_value_create_nint_constant(f, type, val); |
| } |
| else if (type == jit_type_float64) { |
| // Unless the value is "1.0", libjit will store a double constant in |
| // memory, referenced via %ip, and that will blow us up at runtime. Get |
| // it from memory instead (if not 1.0) |
| double val = cfg->getFloatConstValue(((orig) ? orig : this)); |
| if (val == 1.0) |
| jitValue_ = jit_value_create_float64_constant(f, type, val); |
| else { |
| jit_value_t param = cfg->getJitParams()[stackIndex_]; |
| jitValue_ = jit_insn_load_relative(f, param, offset_, type); |
| } |
| } |
| else { |
| Int32 val = (Int32)cfg->getIntConstValue(((orig) ? orig : this)); |
| jitValue_ = jit_value_create_nint_constant(f, type, val); |
| } |
| } |
| else if (isVar()) { |
| jit_value_t param = cfg->getJitParams()[stackIndex_]; |
| |
| // Are we getting the null bit? |
| if (nullBitIndex_ != -1) { |
| // For paranoia, make sure offset_ is not -1 also (indicating packed |
| // format against a varchar, which is not supported yet). |
| assert(offset_ != -1); |
| |
| jit_value_t mask = jit_value_create_nint_constant(f, jit_type_ubyte, |
| (UInt8)0x1 << (7 - (nullBitIndex_ & 7))); |
| |
| jit_value_t nByte = jit_insn_load_relative(f, param, |
| offset_ + (nullBitIndex_ >> 3), jit_type_ubyte); |
| jitValue_ = jit_insn_and(f, nByte, mask); |
| } |
| else |
| jitValue_ = jit_insn_load_relative(f, param, offset_, type); |
| } |
| else { |
| // Accessing an undefined temp is not allowed. |
| assert (FALSE); |
| } |
| |
| jitValueBlock_ = b; |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) { |
| jit_value_t tempVal = jitValue_; |
| jitValueBlock_ = NULL; |
| jitValue_ = jitValuePtr_ = NULL; |
| return tempVal; |
| } |
| |
| return jitValue_; |
| } |
| |
| // |
| // 1. Get string length of varchar and return to caller. |
| // 2. Move pointer past string length field. |
| // 3. If asked to, resize length by subtracting off padding |
| // |
| jit_value_t PCodeCfg::genStringSetup(jit_function_t f, |
| jit_value_t* tStr, |
| PCodeOperand* src, |
| NABoolean padExists = FALSE, |
| NABoolean lenNeeded = TRUE) |
| { |
| jit_value_t lenJitVal = NULL; |
| |
| Int32 vcIndLen = src->getVcIndicatorLen(); |
| |
| // If pad exists, then the length must surely be retrieved. |
| if (padExists) |
| lenNeeded = TRUE; |
| |
| if (vcIndLen <= 0) { |
| // For fixed chars, just record the max length, if length is needed |
| if (lenNeeded) { |
| jit_value_t max; |
| max = jit_value_create_nint_constant(f, jit_type_uint, src->getLen()); |
| |
| lenJitVal = jit_value_create(f, jit_type_uint); |
| jit_insn_store(f, lenJitVal, max); |
| } |
| } |
| else |
| { |
| // Only get length if needed - which is most of the time. |
| if (lenNeeded) { |
| if (vcIndLen == 2) |
| lenJitVal = jit_insn_load_relative(f, *tStr, 0, jit_type_ushort); |
| else |
| lenJitVal = jit_insn_load_relative(f, *tStr, 0, jit_type_uint); |
| } |
| |
| *tStr = jit_insn_add_relative(f, *tStr, vcIndLen); |
| } |
| |
| // If padding exists that needs to be factored into the length, computet it |
| // now with a loop. |
| |
| if (padExists) { |
| jit_value_t temp1, temp2, temp3; |
| jit_value_t spaceJitVal = |
| jit_value_create_nint_constant(f, jit_type_ubyte, ' '); |
| |
| jit_label_t padStartLabel = jit_label_undefined; |
| jit_label_t padEndLabel = jit_label_undefined; |
| |
| jit_insn_label(f, &padStartLabel); |
| jit_insn_branch_if_not(f, lenJitVal, &padEndLabel); |
| |
| temp1 = jit_insn_sub(f, lenJitVal, oneJitVal_); |
| temp2 = jit_insn_load_elem(f, *tStr, temp1, jit_type_ubyte); |
| temp3 = jit_insn_eq(f, temp2, spaceJitVal); |
| jit_insn_branch_if_not(f, temp3, &padEndLabel); |
| |
| jit_insn_store(f, lenJitVal, temp1); |
| jit_insn_branch(f, &padStartLabel); |
| |
| jit_insn_label(f, &padEndLabel); |
| } |
| |
| return lenJitVal; |
| } |
| |
| jit_value_t PCodeCfg::genHash(jit_function_t f, |
| jit_value_t tStr, |
| jit_value_t tStrLen, |
| jit_value_t loopIndex, |
| Int32 constantLen = 0) |
| { |
| // If constantLen is provided (i.e. tStrLen is NULL) then that implies that we |
| // are hashing a standard-sized column. Otherwise we are hashing some kind've |
| // string. |
| |
| Int32 j; |
| |
| jit_value_t t1, t2, t3, t4, t5, t6, resJitVal; |
| jit_label_t startLoop = jit_label_undefined; |
| jit_label_t endLoop = jit_label_undefined; |
| |
| jit_value_t shiftRVal = jit_value_create_nint_constant(f, jit_type_int, 31); |
| |
| // In an effort to reduce space, generate loop for hashing fixed-length |
| // strings greater than a certain length. |
| if ((tStrLen == NULL) && (constantLen > 32)) |
| tStrLen = jit_value_create_nint_constant(f, jit_type_int, constantLen); |
| |
| if (tStrLen == NULL) { |
| t1 = jit_insn_load_relative(f, tStr, 0, jit_type_ubyte); |
| resJitVal = jit_insn_load_elem(f, hashTableJitVal_, t1, jit_type_uint); |
| |
| // Unroll hash using known length |
| for (j=1; j < constantLen; j++) |
| { |
| // |
| // Compute: t1 = src[j] |
| // t2 = randomHashValues[t1] |
| // t3 = resJitVal << 1 |
| // t4 = resJitVal >> 31 |
| // t5 = (t3 | t4) |
| // resJitVal = t5 ^ resJitVal |
| // |
| t1 = jit_insn_load_relative(f, tStr, j, jit_type_ubyte); |
| t2 = jit_insn_load_elem(f, hashTableJitVal_, t1, jit_type_uint); |
| t3 = jit_insn_shl(f, resJitVal, oneJitVal_); |
| t4 = jit_insn_ushr(f, resJitVal, shiftRVal); |
| t5 = jit_insn_or(f, t3, t4); |
| resJitVal = jit_insn_xor(f, t5, t2); |
| } |
| |
| return resJitVal; |
| } |
| |
| // Create temp var to hold result of hashing string. Temp space needs to be |
| // allocated since it can have, by default, the value 0 (if length is 0) |
| resJitVal = jit_value_create(f, jit_type_uint); |
| |
| jit_insn_store(f, resJitVal, zeroJitVal_); |
| jit_insn_store(f, loopIndex, tStrLen); |
| |
| // Loop start |
| jit_insn_label(f, &startLoop); |
| |
| // Branch to end label if loopIndex <= 0 |
| t1 = jit_insn_le(f, loopIndex, zeroJitVal_); |
| jit_insn_branch_if(f, t1, &endLoop); |
| |
| // |
| // Compute: t1 = src[i] |
| // t2 = randomHashValues[t1] |
| // t3 = resJitVal << 1 |
| // t4 = resJitVal >> 31 |
| // t5 = (t3 | t4) |
| // resJitVal = t5 ^ resJitVal |
| // |
| t1 = jit_insn_load_relative(f, tStr, 0, jit_type_ubyte); |
| t2 = jit_insn_load_elem(f, hashTableJitVal_, t1, jit_type_uint); |
| t3 = jit_insn_shl(f, resJitVal, oneJitVal_); |
| t4 = jit_insn_ushr(f, resJitVal, shiftRVal); |
| t5 = jit_insn_or(f, t3, t4); |
| t6 = jit_insn_xor(f, t5, t2); |
| jit_insn_store(f, resJitVal, t6); |
| |
| // Decrement loop index and store |
| t1 = jit_insn_sub(f, loopIndex, oneJitVal_); |
| jit_insn_store(f, loopIndex, t1); |
| |
| // Increment pointer and store |
| t2 = jit_insn_add(f, tStr, oneJitVal_); |
| jit_insn_store(f, tStr, t2); |
| |
| // Branch back to head of loop |
| jit_insn_branch(f, &startLoop); |
| |
| // End label |
| jit_insn_label(f, &endLoop); |
| |
| return resJitVal; |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| |
| // |
| // genMemSetLoop() - generate code to set every element in an long array |
| // to the same value. |
| // |
| void PCodeCfg::genMemSetLoop( IRBldr_t * Bldr |
| , Int32 val |
| , jit_value_t tgtPtr |
| , jit_value_t maxLen |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| UInt8 val1 = (UInt8)val; |
| UInt16 val2 = (val1 << 8) | val1; |
| UInt32 val4 = (val2 << 16) | val2; |
| UInt64 val8 = val4 ; //Note: if we use (val4 << 32) we get C++ error |
| val8 = (val8 << 32) | val8; |
| |
| jit_value_t MultiBytes = ConstantInt::get( int64Ty_ , val8 ); |
| jit_value_t OneByte = ConstantInt::get( int8Ty_ , val1 ); |
| |
| jit_value_t BytesPer, CmpRslt ; |
| jit_value_t RndMaxLen, ByteCtVal ; |
| jit_value_t MaxLen64 ; |
| |
| DPT0( "VV0700: ", VV_BD, "GOT into genMemSetLoop()\n" ); |
| |
| jit_value_t Zero = ConstantInt::get( int64Ty_ , 0 ); |
| |
| llvm::LLVMContext &LLContxt = Bldr->getContext(); |
| llvm::Function *ExpFn = Bldr->GetInsertBlock()->getParent(); |
| |
| p_IR_block_t fastLoopLabel = BasicBlock::Create( LLContxt, "MemSetFastBlk" ); |
| p_IR_block_t endLabel = BasicBlock::Create( LLContxt, "MemSetEndBlk" ); |
| |
| DPT2( "VV0702: ", VV_VD, "fastLoopLabel = %p, endLabel = %p\n", |
| fastLoopLabel, endLabel ); |
| |
| Int32 bytesAtOnce = 8; |
| |
| BytesPer = ConstantInt::get( int64Ty_ , bytesAtOnce ); |
| DPT0( "VV0705: ", VV_VD, |
| "MaxLen64 = Bldr->CreateZExt( maxLen, int64Ty_ , 'ExtMaxLen' )\n" ); |
| MaxLen64 = Bldr->CreateZExt( maxLen, int64Ty_ , "ExtMaxLen" ); |
| |
| DPT0( "VV0706: ", VV_VD, |
| "RndMaxLen = Bldr->CreateUDiv( MaxLen64, BytesPer, 'UDiv' )\n" ); |
| RndMaxLen = Bldr->CreateUDiv( MaxLen64, BytesPer, "UDiv" ); |
| |
| DPT0( "VV0707: ", VV_VD, |
| "RndMaxLen = Bldr->CreateMul( RndMaxLen, BytesPer, 'Mul' )\n" ); |
| RndMaxLen = Bldr->CreateMul( RndMaxLen, BytesPer, "Mul" ); |
| |
| DPT0( "VV0710: ", VV_VD, |
| "AllocaInst * ByteCt = Bldr->CreateAlloca( int64Ty_ )\n" ); |
| AllocaInst * ByteCt = Bldr->CreateAlloca( int64Ty_ ); |
| |
| DPT0( "VV0711: ", VV_VD, |
| "Bldr->CreateStore( Zero, ByteCt )\n" ); |
| Bldr->CreateStore( Zero, ByteCt ); |
| |
| DPT0( "VV0712: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpULT( RndMaxLen, BytesPer, 'ICmp.RndMaxLen' )\n" ); |
| CmpRslt = Bldr->CreateICmpULT( RndMaxLen, BytesPer, "ICmp.RndMaxLen" ); |
| |
| DPT0( "VV0713: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, endLabel, fastLoopLabel )\n" ); |
| Bldr->CreateCondBr( CmpRslt, endLabel, fastLoopLabel ); |
| |
| // Start fast loop here |
| |
| DPT1( "VV0715: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( fastLoopLabel = %p )\n" , fastLoopLabel ); |
| ExpFn->getBasicBlockList().push_back( fastLoopLabel ); |
| |
| DPT0( "VV0716: ", VV_VD, |
| "Bldr->SetInsertPoint( fastLoopLabel )\n" ); |
| Bldr->SetInsertPoint( fastLoopLabel ); |
| |
| // Copy multiple bytes at a time. |
| DPT0( "VV0718: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); // Re-load within the loop |
| |
| DPT0( "VV0719: ", VV_VD, |
| "ThisTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, 'ThisTgt' )\n" ); |
| jit_value_t ThisTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, "ThisTgt" ); |
| |
| IR_StoreRelativeWithType( Bldr, MultiBytes, ThisTgt, |
| 0, int64Ty_ ); |
| |
| // Increment count of bytes handled |
| DPT0( "VV0721: ", VV_VD, |
| "ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, 'nextIncr')\n"); |
| ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, "nextIncr" ); |
| |
| DPT0( "VV0722: ", VV_VD, |
| "Bldr->CreateStore( ByteCtVal, ByteCt, 'storeByteCt' )\n" ); |
| Bldr->CreateStore( ByteCtVal, ByteCt, "storeByteCt" ); |
| |
| // while (ByteCtVal < RndMaxLen) branch to fastLoop |
| DPT0( "VV0723: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpULT( ByteCtVal, RndMaxLen, 'ICmp.ByteCt' )\n" ); |
| CmpRslt = Bldr->CreateICmpULT( ByteCtVal, RndMaxLen, "ICmp.ByteCt" ); |
| |
| DPT0( "VV0724: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, fastLoopLabel, endLabel )\n" ); |
| Bldr->CreateCondBr( CmpRslt, fastLoopLabel, endLabel ); |
| |
| DPT1( "VV0725: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( endLabel = %p )\n" , endLabel ); |
| ExpFn->getBasicBlockList().push_back( endLabel ); |
| |
| DPT0( "VV0726: ", VV_VD, |
| "Bldr->SetInsertPoint( endLabel )\n" ); |
| Bldr->SetInsertPoint( endLabel ); |
| |
| // Now copy any remaining bytes (from 0 to 7 bytes are possible) |
| |
| p_IR_block_t slowLoopLabel = BasicBlock::Create( LLContxt, "MemSetSlowBlk" ); |
| p_IR_block_t end2Label = BasicBlock::Create( LLContxt, "MemSetEndBlk" ); |
| |
| DPT2( "VV0728: ", VV_VD, "slowLoopLabel = %p, end2Label = %p\n", |
| slowLoopLabel, end2Label ); |
| |
| bytesAtOnce = 1; |
| |
| BytesPer = ConstantInt::get( int64Ty_ , bytesAtOnce ); |
| |
| DPT0( "VV0730: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); |
| |
| DPT0( "VV0732: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpUGE( ByteCtVal, MaxLen64, 'ICmp.RndMaxLen' )\n" ); |
| CmpRslt = Bldr->CreateICmpUGE( ByteCtVal, MaxLen64, "ICmp.RndMaxLen" ); |
| |
| DPT0( "VV0733: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, end2Label, slowLoopLabel )\n" ); |
| Bldr->CreateCondBr( CmpRslt, end2Label, slowLoopLabel ); |
| |
| // Start slow loop here |
| |
| DPT1( "VV0735: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( slowLoopLabel = %p )\n", slowLoopLabel ); |
| ExpFn->getBasicBlockList().push_back( slowLoopLabel ); |
| |
| DPT0( "VV0736: ", VV_VD, |
| "Bldr->SetInsertPoint( slowLoopLabel )\n" ); |
| Bldr->SetInsertPoint( slowLoopLabel ); |
| |
| // Copy multiple bytes at a time. |
| DPT0( "VV0738: ", VV_VD, |
| "ByteCtVal = Bldr->CreateLoad( ByteCt, 'loadByteCt' )\n"); |
| ByteCtVal = Bldr->CreateLoad( ByteCt, "loadByteCt" ); // Re-load within the loop |
| |
| DPT0( "VV0739: ", VV_VD, |
| "CurrTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, 'CurrTgt' )\n" ); |
| jit_value_t CurrTgt = Bldr->CreateGEP( tgtPtr, ByteCtVal, "CurrTgt" ); |
| |
| IR_StoreRelativeWithType( Bldr, OneByte, CurrTgt, |
| 0, int8Ty_ ); |
| |
| // Increment count of bytes handled |
| DPT0( "VV0740: ", VV_VD, |
| "ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, 'nextIncr')\n"); |
| ByteCtVal = Bldr->CreateAdd( ByteCtVal, BytesPer, "nextIncr" ); |
| |
| DPT0( "VV0742: ", VV_VD, |
| "Bldr->CreateStore( ByteCtVal, ByteCt, 'storeByteCt' )\n" ); |
| Bldr->CreateStore( ByteCtVal, ByteCt, "storeByteCt" ); |
| |
| |
| // while (ByteCtVal < MaxLen64) branch to slowLoop |
| DPT0( "VV0743: ", VV_VD, |
| "CmpRslt = Bldr->CreateICmpULT( ByteCtVal, MaxLen64, 'ICmp.ByteCt' )\n" ); |
| CmpRslt = Bldr->CreateICmpULT( ByteCtVal, MaxLen64, "ICmp.ByteCt" ); |
| |
| DPT0( "VV0744: ", VV_VD, |
| "Bldr->CreateCondBr( CmpRslt, slowLoopLabel, end2Label )\n" ); |
| Bldr->CreateCondBr( CmpRslt, slowLoopLabel, end2Label ); |
| |
| DPT1( "VV0745: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( end2Label = %p )\n", end2Label ); |
| ExpFn->getBasicBlockList().push_back( end2Label ); |
| |
| DPT0( "VV0746: ", VV_VD, |
| "Bldr->SetInsertPoint( end2Label )\n" ); |
| Bldr->SetInsertPoint( end2Label ); |
| } |
| |
| void PCodeCfg::genUnalignedMemset( IRBldr_t * Bldr |
| , jit_value_t tgtPtr |
| , Int32 val |
| , Int32 length |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| Int32 i; |
| UInt8 val1 = (UInt8)val; |
| UInt16 val2 = (val1 << 8) | val1; |
| UInt32 val4 = (val2 << 16) | val2; |
| UInt64 val8 = val4 ; //Note: if we use (val4 << 32) we get C++ error |
| val8 = (val8 << 32) | val8; |
| |
| if ( length < 32 ) |
| { |
| // First try multiples of 8 |
| //// jit_value_t jVal8 = jit_value_create_nint_constant(f, jit_type_uint, val8); |
| jit_value_t jVal8 = ConstantInt::get( int64Ty_, val8 ); |
| |
| for (i=0; length >= 8; i+=8, length-=8) { |
| //// jit_insn_store_relative(f, Tgt, i, jVal8); |
| |
| DPT0( "VV0750: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, jVal8, tgtPtr, i, int64Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, jVal8, tgtPtr, i, int64Ty_ ); |
| } |
| |
| // Then try multiples of 4 |
| //// jit_value_t jVal4 = jit_value_create_nint_constant(f, jit_type_uint, val4); |
| jit_value_t jVal4 = ConstantInt::get( int32Ty_, val4 ); |
| |
| for (i=0; length >= 4; i+=4, length-=4) { |
| //// jit_insn_store_relative(f, Tgt, i, jVal4); |
| |
| DPT0( "VV0760: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, jVal4, tgtPtr, i, int32Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, jVal4, tgtPtr, i, int32Ty_ ); |
| } |
| |
| // Then try multiples of 2 |
| //// jit_value_t jVal2 = jit_value_create_nint_constant(f, jit_type_ushort, val2); |
| jit_value_t jVal2 = ConstantInt::get( int16Ty_, val2 ); |
| |
| for (; length >= 2; i+=2, length-=2) { |
| //// jit_insn_store_relative(f, Tgt, i, jVal2); |
| |
| DPT0( "VV0770: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, jVal2, tgtPtr, i, int16Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, jVal2, tgtPtr, i, int16Ty_ ); |
| } |
| |
| // Lastly copy 1 byte at a time |
| //// jit_value_t jVal1 = jit_value_create_nint_constant(f, jit_type_ubyte, val1); |
| jit_value_t jVal1 = ConstantInt::get( int8Ty_, val1 ); |
| |
| for (; length >= 1; i+=1, length-=1) { |
| //// jit_insn_store_relative(f, Tgt, i, jVal1); |
| |
| DPT0( "VV0780: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, jVal1, tgtPtr, i, int8Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, jVal1, tgtPtr, i, int8Ty_ ); |
| } |
| |
| } // End: if ( length < 32 ) |
| |
| else // long, fixed-length string ... use a loop instead of voluminous instruction generation |
| { |
| jit_value_t ConstLen = ConstantInt::get( int64Ty_, length ); |
| |
| genMemSetLoop( Bldr, val, tgtPtr, ConstLen ); |
| } |
| |
| return; |
| } |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| |
| void PCodeCfg::genUnalignedMemset(jit_function_t f, |
| jit_value_t tgt, |
| Int32 val, |
| Int32 length) |
| { |
| Int32 i; |
| |
| #if 0 |
| // For lengths <= 32, jit_insn_memset can be called to generate the code. |
| // Anything greater and an intrinsic call is made. UPDATE: This is true only |
| // when jit_optimization_level is 0. If the optimization level is higher, |
| // then the cutoff is 16 (not 32). The best thing is to generate the code |
| // ourselves. |
| if (length <= 32) { |
| jit_value_t jVal = jit_value_create_nint_constant(f, jit_type_int, val); |
| jit_value_t jLen = jit_value_create_nint_constant(f, jit_type_int, length); |
| |
| jit_insn_memset(f, tgt, jVal, jLen); |
| |
| return; |
| } |
| #endif |
| |
| UInt8 val1 = (UInt8)val; |
| UInt16 val2 = (val1 << 8) | val1; |
| UInt32 val4 = (val2 << 16) | val2; |
| |
| // First try multiples of 4 |
| jit_value_t jVal4 = jit_value_create_nint_constant(f, jit_type_uint, val4); |
| for (i=0; length >= 4; i+=4, length-=4) { |
| jit_insn_store_relative(f, tgt, i, jVal4); |
| } |
| |
| // Then try multiples of 2 |
| jit_value_t jVal2 = jit_value_create_nint_constant(f, jit_type_ushort, val2); |
| for (; length >= 2; i+=2, length-=2) { |
| jit_insn_store_relative(f, tgt, i, jVal2); |
| } |
| |
| // Lastly copy 1 byte at a time |
| jit_value_t jVal1 = jit_value_create_nint_constant(f, jit_type_ubyte, val1); |
| for (; length >= 1; i+=1, length-=1) { |
| jit_insn_store_relative(f, tgt, i, jVal1); |
| } |
| |
| return; |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| void PCodeCfg::genUnalignedMemcpy( IRBldr_t * Bldr |
| , jit_value_t tgt |
| , jit_value_t src |
| , jit_value_t len |
| , Int32 constantLen = 0 |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| DPT0( "VV0800: ", VV_BD, "GOT into genUnalignedMemcpy()\n" ); |
| |
| // If dealing with a *short* fixed-length string ... |
| // Note: The 32 in the next line is arbitrary. We just don't want |
| // to generate dozens or even hundreds or thousands of load/store instructions. |
| if ( (len == NULL) && (constantLen < 32) ) |
| { |
| Int32 i, length = constantLen; |
| |
| DPT0( "VV0810: ", VV_BD, |
| " GOT into genUnalignedMemcpy() with short fixed-length string\n" ); |
| |
| // First try multiples of 8 |
| for (i=0; length >= 8; i+=8, length-=8) |
| { |
| jit_value_t val = IR_LoadRelativeWithType( Bldr, src, i, int64Ty_ ); |
| |
| DPT0( "VV0812: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, val, tgt, i, int64Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, val, tgt, i, int64Ty_ ); |
| } |
| |
| // Then try multiples of 4 |
| for (; length >= 4; i+=4, length-=4) |
| { |
| //// jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_uint); |
| //// jit_insn_store_relative(f, tgt, i, val); |
| |
| jit_value_t val = IR_LoadRelativeWithType( Bldr, src, i, int32Ty_ ); |
| |
| DPT0( "VV0814: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, val, tgt, i, int32Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, val, tgt, i, int32Ty_ ); |
| } |
| |
| // Then try multiples of 2 |
| for (; length >= 2; i+=2, length-=2) |
| { |
| //// jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_ushort); |
| //// jit_insn_store_relative(f, tgt, i, val); |
| |
| jit_value_t val = IR_LoadRelativeWithType( Bldr, src, i, int16Ty_ ); |
| |
| DPT0( "VV0816: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, val, tgt, i, int16Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, val, tgt, i, int16Ty_ ); |
| } |
| |
| // Lastly copy 1 byte at a time |
| for (; length >= 1; i+=1, length-=1) |
| { |
| //// jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_ubyte); |
| //// jit_insn_store_relative(f, tgt, i, val); |
| |
| jit_value_t val = IR_LoadRelativeWithType( Bldr, src, i, int8Ty_ ); |
| |
| DPT0( "VV0819: ", VV_VD, |
| "IR_StoreRelativeWithType( Bldr, val, tgt, i, int8Ty_ )\n" ); |
| IR_StoreRelativeWithType( Bldr, val, tgt, i, int8Ty_ ); |
| } |
| |
| return; |
| |
| } // End: if ( (len == NULL) && (constantLen < 32) ) |
| |
| else if ( len == NULL ) // *long* fixed-length string |
| { |
| DPT0( "VV0820: ", VV_BD, |
| "GOT into genUnalignedMemcpy() with long fixed-length string\n" ); |
| |
| jit_value_t ConstLen = ConstantInt::get( int64Ty_, constantLen ); |
| |
| genMemCopyLoop( Bldr, src, tgt, ConstLen ); |
| } |
| else // len != NULL |
| { |
| DPT0( "VV0830: ", VV_BD, |
| "GOT into genUnalignedMemcpy() with len != NULL ptr\n" ); |
| |
| genMemCopyLoop( Bldr, src, tgt, len ); |
| } |
| |
| return; |
| } |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| |
| void PCodeCfg::genUnalignedMemcpy(jit_function_t f, |
| jit_value_t tgt, |
| jit_value_t src, |
| jit_value_t len, |
| Int32 constantLen = 0) |
| { |
| // |
| // Upon entering this routine, tgt, src, and len should all be temp operands |
| // that were already initialized by caller. len may be NULL, however, |
| // indicating that a constant length (stored in "constantLen") is provided. |
| // In this case, we attempt to use wide loads and stores to implement the |
| // copy. |
| // |
| |
| jit_value_t comp, val, temp1, temp2, temp3; |
| |
| jit_label_t fastLoopLabel = jit_label_undefined; |
| jit_label_t remainderLabel = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| |
| jit_value_t max = jit_value_create_nint_constant(f, jit_type_int, 4); |
| |
| if (len == NULL) { |
| Int32 i, length = constantLen; |
| |
| // First try multiples of 4 |
| for (i=0; length >= 4; i+=4, length-=4) { |
| jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_uint); |
| jit_insn_store_relative(f, tgt, i, val); |
| } |
| |
| // Then try multiples of 2 |
| for (; length >= 2; i+=2, length-=2) { |
| jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_ushort); |
| jit_insn_store_relative(f, tgt, i, val); |
| } |
| |
| // Lastly copy 1 byte at a time |
| for (; length >= 1; i+=1, length-=1) { |
| jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_ubyte); |
| jit_insn_store_relative(f, tgt, i, val); |
| } |
| |
| return; |
| } |
| |
| // Initial check for entering fast loop (i.e. if len >= max) |
| comp = jit_insn_lt(f, len, max); |
| jit_insn_branch_if(f, comp, &remainderLabel); |
| |
| // Start fast loop here |
| jit_insn_label(f, &fastLoopLabel); |
| |
| // Copy 4 bytes at a time. |
| val = jit_insn_load_relative(f, src, 0, jit_type_uint); |
| jit_insn_store_relative(f, tgt, 0, val); |
| |
| // Decrement loop index |
| temp1 = jit_insn_sub(f, len, max); |
| jit_insn_store(f, len, temp1); |
| |
| // Increment string pointers |
| temp2 = jit_insn_add(f, tgt, max); |
| temp3 = jit_insn_add(f, src, max); |
| jit_insn_store(f, tgt, temp2); |
| jit_insn_store(f, src, temp3); |
| |
| // while (len >= 4) branch to fastLoop |
| comp = jit_insn_ge(f, len, max); |
| jit_insn_branch_if(f, comp, &fastLoopLabel); |
| |
| // |
| // Start of remainder loop |
| // |
| |
| jit_insn_label(f, &remainderLabel); |
| |
| // Branch to end label if len <= 0 |
| comp = jit_insn_le(f, len, zeroJitVal_); |
| jit_insn_branch_if(f, comp, &endLabel); |
| |
| // Copy 1 byte at a time. |
| val = jit_insn_load_relative(f, src, 0, jit_type_ubyte); |
| jit_insn_store_relative(f, tgt, 0, val); |
| |
| // Decrement loop index |
| temp1 = jit_insn_sub(f, len, oneJitVal_); |
| jit_insn_store(f, len, temp1); |
| |
| // Increment string pointers |
| temp2 = jit_insn_add(f, tgt, oneJitVal_); |
| temp3 = jit_insn_add(f, src, oneJitVal_); |
| jit_insn_store(f, tgt, temp2); |
| jit_insn_store(f, src, temp3); |
| |
| jit_insn_branch(f, &remainderLabel); |
| |
| |
| // End label |
| jit_insn_label(f, &endLabel); |
| } |
| |
| #if 0 |
| void PCodeCfg::genUnalignedPadCheck(jit_function_t f, |
| jit_value_t src, |
| jit_value_t len, |
| Int32 constantLen = 0) |
| { |
| // Upon entering this routine, src, and len should all be temp operands |
| // that were already initialized by caller. len may be NULL, however, |
| // indicating that a constant length (stored in "constantLen") is provided. |
| // In this case, we attempt to use wide loads and stores to implement the |
| // pad comparison |
| |
| if (len == NULL) { |
| } |
| } |
| #endif |
| |
| #if 0 |
| void PCodeCfg::genUnalignedMemcmp(jit_function_t f, |
| jit_value_t tgt, |
| jit_value_t src, |
| jit_value_t len, |
| Int32 constantLen = 0) |
| { |
| // |
| // Upon entering this routine, tgt, src, and len should all be temp operands |
| // that were already initialized by caller. len may be NULL, however, |
| // indicating that a constant length (stored in "constantLen") is provided. |
| // In this case, we attempt to use wide loads and stores to implement the |
| // compare. |
| // |
| |
| jit_value_t comp, val, temp1, temp2, temp3; |
| |
| jit_label_t fastLoopLabel = jit_label_undefined; |
| jit_label_t remainderLabel = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| |
| jit_value_t max = jit_value_create_nint_constant(f, jit_type_int, 4); |
| |
| if (len == NULL) { |
| Int32 i, length = constantLen; |
| |
| // First try multiples of 4 |
| for (i=0; length >= 4; i+=4, length-=4) { |
| jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_uint); |
| jit_insn_store_relative(f, tgt, i, val); |
| } |
| |
| // Then try multiples of 2 |
| for (; length >= 2; i+=2, length-=2) { |
| jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_ushort); |
| jit_insn_store_relative(f, tgt, i, val); |
| } |
| |
| // Lastly copy 1 byte at a time |
| for (; length >= 1; i+=1, length-=1) { |
| jit_value_t val = jit_insn_load_relative(f, src, i, jit_type_ubyte); |
| jit_insn_store_relative(f, tgt, i, val); |
| } |
| |
| return; |
| } |
| |
| // Initial check for entering fast loop (i.e. if len >= max) |
| comp = jit_insn_lt(f, len, max); |
| jit_insn_branch_if(f, comp, &remainderLabel); |
| |
| // Start fast loop here |
| jit_insn_label(f, &fastLoopLabel); |
| |
| // Copy 4 bytes at a time. |
| val = jit_insn_load_relative(f, src, 0, jit_type_uint); |
| jit_insn_store_relative(f, tgt, 0, val); |
| |
| // Decrement loop index |
| temp1 = jit_insn_sub(f, len, max); |
| jit_insn_store(f, len, temp1); |
| |
| // Increment string pointers |
| temp2 = jit_insn_add(f, tgt, max); |
| temp3 = jit_insn_add(f, src, max); |
| jit_insn_store(f, tgt, temp2); |
| jit_insn_store(f, src, temp3); |
| |
| // while (len >= 4) branch to fastLoop |
| comp = jit_insn_ge(f, len, max); |
| jit_insn_branch_if(f, comp, &fastLoopLabel); |
| |
| // |
| // Start of remainder loop |
| // |
| |
| jit_insn_label(f, &remainderLabel); |
| |
| // Branch to end label if len <= 0 |
| comp = jit_insn_le(f, len, zeroJitVal_); |
| jit_insn_branch_if(f, comp, &endLabel); |
| |
| // Copy 1 byte at a time. |
| val = jit_insn_load_relative(f, src, 0, jit_type_ubyte); |
| jit_insn_store_relative(f, tgt, 0, val); |
| |
| // Decrement loop index |
| temp1 = jit_insn_sub(f, len, oneJitVal_); |
| jit_insn_store(f, len, temp1); |
| |
| // Increment string pointers |
| temp2 = jit_insn_add(f, tgt, oneJitVal_); |
| temp3 = jit_insn_add(f, src, oneJitVal_); |
| jit_insn_store(f, tgt, temp2); |
| jit_insn_store(f, src, temp3); |
| |
| jit_insn_branch(f, &remainderLabel); |
| |
| |
| // End label |
| jit_insn_label(f, &endLabel); |
| } |
| #endif |
| |
| void PCodeCfg::genBignumSub(PCodeCfg* cfg, |
| jit_function_t f, |
| PCodeOperand* res, |
| jit_value_t src1, |
| jit_value_t src2, |
| jit_value_t sign1, |
| jit_value_t sign2, |
| jit_value_t tSrc1, |
| jit_value_t tSrc2, |
| PCodeBlock* block) |
| { |
| Int32 i; |
| |
| jit_value_t t1, t2, t3, t4, t5, t6 = NULL, carry = NULL; |
| jit_label_t keepStringsLabel = jit_label_undefined; |
| jit_label_t switchStringsLabel = jit_label_undefined; |
| |
| jit_value_t jitValMask16 = |
| jit_value_create_nint_constant(f, jit_type_ushort, 0x8000); |
| jit_value_t jitValNotMask16 = |
| jit_value_create_nint_constant(f, jit_type_ushort, 0x7fff); |
| jit_value_t jitValNotMask32 = |
| jit_value_create_nint_constant(f, jit_type_ushort, 0x7fffffff); |
| |
| jit_value_t jitValUpper32 = |
| jit_value_create_nint_constant(f, jit_type_int, 0x10000); |
| |
| Int32 len = res->getLen(); |
| Int32 len16 = len >> 1; |
| |
| Int32 bignumSize = len16; |
| jit_type_t bignumType = jit_type_ushort; |
| jit_value_t bignumNotMask = jitValNotMask16; |
| |
| // If we can process the bignum faster in chunks of 32-bits, we will. |
| if ((len % 4) == 0) { |
| bignumSize = len >> 2; |
| bignumType = jit_type_uint; |
| bignumNotMask = jitValNotMask32; |
| } |
| |
| // Assume by default that the source order is correct - i.e. src1 has a |
| // bigger magnitude that src2. |
| jit_insn_store(f, tSrc1, src1); |
| jit_insn_store(f, tSrc2, src2); |
| |
| // Which string is bigger? |
| for (i=bignumSize-1; i >= 0; i--) { |
| if (i == (bignumSize-1)) { |
| // Need to compare without sign bit. |
| t1 = jit_insn_and(f, sign1, bignumNotMask); |
| t2 = jit_insn_and(f, sign2, bignumNotMask); |
| |
| // Store back into the source strings w/o sign bit enabled |
| jit_insn_store_relative(f, tSrc1, i, t1); |
| jit_insn_store_relative(f, tSrc2, i, t2); |
| } |
| else { |
| t1 = jit_insn_load_relative(f, tSrc1, i, bignumType); |
| t2 = jit_insn_load_relative(f, tSrc2, i, bignumType); |
| } |
| |
| t3 = jit_insn_gt(f, t1, t2); |
| jit_insn_branch_if(f, t3, &keepStringsLabel); |
| |
| // No need to do switcharoo comparison if this is the last one. src1 will |
| // either be equal or less that src2. Since the chances of the two being |
| // equal are unlikely, we assume not and always do a switcharoo. |
| // |
| // BTW, if both sources are equal, this is an example where we can have -0 |
| // emitted. This is because, depending on which source we say is "bigger", |
| // if the bigger one is negative, that's what the result will be. |
| if (i != 0) { |
| t3 = jit_insn_lt(f, t1, t2); |
| jit_insn_branch_if(f, t3, &switchStringsLabel); |
| } |
| } |
| |
| // Do the switcharoo |
| jit_insn_label(f, &switchStringsLabel); |
| jit_insn_store(f, tSrc1, src2); |
| jit_insn_store(f, tSrc2, src1); |
| |
| // Keep things the same. |
| jit_insn_label(f, &keepStringsLabel); |
| |
| // Now let's load up the result jit value. |
| jit_value_t resJitVal = res->getJitValue(cfg, f, res->getJitType(), block); |
| |
| // Now start performing the subs. Must do it 2-bytes at a time because libjit |
| // doesn't support various 64-bit ops yet. |
| for (i=0; i < len16; i++) |
| { |
| // |
| // Perform: t6 = ((Int32)src1[i] - (Int32)src2[i]) - (carry) |
| // No need to subtract carry if this is the first time through. |
| // |
| t1 = jit_insn_load_relative(f, tSrc1, i, jit_type_ushort); |
| t2 = jit_insn_load_relative(f, tSrc2, i, jit_type_ushort); |
| t3 = jit_insn_convert(f, t1, jit_type_int, 0); |
| t4 = jit_insn_convert(f, t2, jit_type_int, 0); |
| t5 = jit_insn_sub(f, t3, t4); |
| t6 = (i != 0) ? jit_insn_sub(f, t5, carry) : t5; |
| |
| // Perform: t4 = ((t6 + 0x10000) & 0xffff) |
| t3 = jit_insn_add(f, t6, jitValUpper32); |
| t4 = jit_insn_convert(f, t3, jit_type_ushort, 0); |
| |
| // If this is not the last short to subtrace, store the result and identify |
| // a potential carry. |
| if (i != (len16-1)) { |
| jit_insn_store_relative(f, resJitVal, i, t4); |
| carry = jit_insn_lt(f, t6, zeroJitVal_); |
| } |
| else { |
| // Use "carry" to hold the sign value of src1. |
| carry = jit_insn_and(f, t1, jitValMask16); |
| |
| // Now insert the sign bit into the final result. |
| t6 = jit_insn_or(f, t4, carry); |
| |
| // Final result short is stored after source strings are updated with |
| // their sign bits (so that we avoid situations like "A = A - B". |
| } |
| } |
| |
| // Reset sign in source |
| jit_insn_store_relative(f, src1, bignumSize-1, sign1); |
| jit_insn_store_relative(f, src2, bignumSize-1, sign2); |
| |
| // Store final res value here. |
| jit_insn_store_relative(f, resJitVal, len16-1, t6); |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| |
| // FIX: Overlapped types can have problems too |
| void PCodeOperand::storeJitValue( PCodeCfg * cfg |
| , IRBldr_t * Bldr |
| , jit_type_t IRtype |
| , jit_value_t value |
| , PCodeBlock * b |
| , jit_value_t * len = NULL |
| , NABoolean noSave = FALSE |
| ) |
| { |
| #if NExprDbgLvl >= VV_NO |
| char NExBuf[500]; |
| #endif |
| CDPT3( "VV0900: ", VV_BD, "In storeJitValue() on PCode Operand at %p, IRtype=%p, " |
| "value=%p\n", this, IRtype, value ); |
| |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| |
| CDPT2( "VV0902: ", VV_BD, "In storeJitValue(): operand=%p, this=%p\n", operand, this ); |
| |
| if (operand != this) |
| return operand->storeJitValue(cfg, Bldr, IRtype, value, b, len, noSave); |
| |
| jit_type_t valType = value->getType() ; |
| |
| // |
| // Are we being asked to perform a memcpy? |
| // |
| if ( valType->isPointerTy() ) |
| { |
| jit_value_t size = |
| ((len) ? *len : ConstantInt::get( cfg->getInt64Ty(), getLen() ) ); |
| |
| if (jitValuePtr_) |
| { |
| CDPT0( "VV0904: ", VV_BD, "In storeJitValue, found jitValuePtr_ non-null\n"); |
| |
| assert(jitValuePtrBlock_ != NULL); |
| |
| // If the PCBlock given in jitValuePtrBlock_ dominates PCBlock b, |
| // then we are assured that jitValuePtr_ is valid. |
| // |
| if (!b->onesVector.testBit(jitValuePtrBlock_->getBlockNum())) |
| jitValuePtr_ = NULL; |
| } |
| |
| if (!jitValuePtr_) |
| { |
| CDPT0( "VV0906: ", VV_BD, "In storeJitValue, found jitValuePtr_ to be NULL\n"); |
| |
| if (isVar() || isNonNativeTemp()) |
| { |
| CDPT1( "VV0908: ", VV_BD, "In storeJitValue, getting param using stackIndex_ = " |
| "%d\n", stackIndex_); |
| |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| |
| CDPT0( "VV0910: ", VV_BD, |
| "param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() )\n" ); |
| jit_value_t param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() ); |
| |
| //// jitValuePtr_ = jit_insn_add_relative(f, param, offset_); */ |
| |
| CDPT1( "VV0912: ", VV_BD, "In storeJitValue, getting param using offset_ = " |
| "%d\n", offset_); |
| |
| jit_value_t tmp1 = ConstantInt::get( cfg->getInt64Ty(), offset_ ) ; |
| |
| CDPT1( "VV0914: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreateGEP( param, tmp1 = %d )\n", offset_ ); |
| jitValuePtr_ = Bldr->CreateGEP( param, tmp1 ); |
| } |
| else if ( jitValue_ ) // If space already allocated |
| { |
| CDPT0( "VV0918: ", VV_BD, |
| "jitValuePtr_ = Bldr->CreateGEP( jitValue_, cfg->getZeroJitVal() )\n" ); |
| jitValuePtr_ = Bldr->CreateGEP( jitValue_, cfg->getZeroJitVal() ); |
| } |
| else |
| { |
| assert(0==390); // ZZZZ FIX THIS IF WE EVER GET HERE. |
| #if 0 /* FIX THIS IF WE EVER GET HERE. */ |
| // FIXME: This needs to change. We need to allocate the temp globally |
| // so that references are available everywhere. Best solution is to |
| // pass in temp array and use that. |
| jitValuePtr_ = jit_insn_alloca(size); |
| #endif /* FIX THIS */ |
| } |
| |
| CDPT2( "VV0919: ", VV_BD, "In storeJitValue(): setting jitValuePtrBlock_ = %p " |
| "for PCop = %p\n", b, this ); |
| jitValuePtrBlock_ = b; |
| |
| } // End: if (!jitValuePtr_) |
| |
| CDPT1( "VV0920: ", VV_BD, "In storeJitValue, calling genUnalignedMemcpy() " |
| "with length=%d\n", getLen() ); |
| |
| // Generate unaligned memcpy instead |
| ////// jit_insn_memcpy(f, jitValuePtr_, value, size); |
| ////cfg->genUnalignedMemcpy(f, jitValuePtr_, value, NULL, getLen()); |
| |
| cfg->genUnalignedMemcpy( Bldr, jitValuePtr_, value, NULL, getLen()); |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) |
| { |
| jitValueBlock_ = NULL; |
| jitValuePtrBlock_ = NULL; |
| |
| if ( jitValue_ ) |
| CDPT2( "VV0925: ", VV_BD, "In storeJitValue(): NULLing jitValue_ at %p " |
| "-- in PCodeOp at %p\n", &jitValue_ , this); |
| |
| jitValue_ = jitValuePtr_ = NULL; |
| } |
| |
| return; |
| |
| } // End: if ( valType->isPointerTy() ) |
| |
| // |
| // Peforming standard sized moves |
| // |
| |
| if (isVar()) |
| { |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| |
| CDPT0( "VV0940: ", VV_BD, |
| "param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() )\n" ); |
| jit_value_t param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() ); |
| |
| ////jit_insn_store_relative(param, offset_, value); |
| |
| CDPT0( "VV0942: ", VV_BD, |
| "cfg->IR_StoreRelativeWithType( Bldr, value, param, offset_, IRtype )\n"); |
| cfg->IR_StoreRelativeWithType( Bldr, value, param, offset_, IRtype ); |
| } |
| else |
| { |
| assert (isTemp()); |
| |
| #if 0 |
| // Just set the value to be the new jitValue |
| // FIX: this is ripe for error :( |
| jitValue_ = value; |
| #endif |
| |
| CDPT2( "VV0943: ", VV_BD, "For PCodeOp at %p, Curr Value of jitValue_ = %p\n", |
| this, jitValue_ ); |
| if (!jitValue_) |
| { |
| //// jitValue_ = value; // SEE 'ripe for error' comment above. |
| |
| CDPT0( "VV0944: ", VV_BD, |
| "jitValue_ = (llvm::Value *)Bldr->CreateAlloca( valType )\n" ); |
| jitValue_ = (llvm::Value *)Bldr->CreateAlloca( valType ); |
| |
| CDPT2( "VV0945: ", VV_BD, "Just set jitValue_ in PCodeOp at %p to %p " |
| "via CreateAlloca()\n", this, jitValue_); |
| } |
| else |
| { |
| // If this PC block is not dominated by the previous block containing the |
| // first jitValue_, then things like a jitValuePtr_ need to be reset. |
| // Note, the definition of jitValue_ does not need to dominate this block |
| // since when the value is created (as it is above), it is done so upon |
| // entry to the routine (and therefore available everywhere). Addresses |
| // are not, however, and therefore may need to be recalculated. |
| if ( jitValuePtr_ && |
| ( ( ! b->onesVector.testBit(jitValuePtrBlock_->getBlockNum()) ) || |
| ( jitValueBlock_ && |
| ( !b->onesVector.testBit(jitValueBlock_->getBlockNum()) ) ) |
| ) |
| ) |
| jitValuePtr_ = NULL; |
| |
| } |
| |
| CDPT1( "VV0946: ", VV_BD, "Value's Type ID is %d\n", (int) valType->getTypeID() ); |
| CDPT1( "VV0947: ", VV_BD, "jitValue_'s Type ID is %d\n", |
| (int) jitValue_->getType()->getTypeID() ); |
| |
| #if NExprDbgLvl >= VV_BD |
| if ( jitValue_->getType()->isPointerTy() ) |
| CDPT1( "VV0948: ", VV_BD, "jitValue_ is PTR to type ID %d\n", |
| jitValue_->getType()->getContainedType(0)->getTypeID() ); |
| #endif // NExprDbgLvl >= VV_BD |
| |
| |
| ////jit_insn_store(f, jitValue_, value); |
| |
| CDPT0( "VV0949: ", VV_BD, |
| "jit_value_t storePtr = Bldr->CreatePointerCast( jitValue_, valType->getPointerTo() )\n" ); |
| jit_value_t storePtr = Bldr->CreatePointerCast( jitValue_, valType->getPointerTo() ); |
| |
| CDPT0( "VV0950: ", VV_BD, |
| "Bldr->CreateStore( value, storePtr )\n" ); |
| Bldr->CreateStore( value, storePtr ); |
| |
| |
| CDPT2( "VV0951: ", VV_BD, "In storeJitValue(): setting jitValueBlock_ = %p " |
| "for PCop = %p\n", b, this ); |
| jitValueBlock_ = b; |
| } |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) |
| { |
| jitValueBlock_ = NULL; |
| jitValuePtrBlock_ = NULL; |
| |
| CDPT2( "VV0952: ", VV_BD, "NULLing jitValue_ at %p -- in PCodeOp at %p\n", |
| &jitValue_ , this ); |
| jitValue_ = jitValuePtr_ = NULL; |
| } |
| } |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| // FIX: Overlapped types can have problems too |
| void PCodeOperand::storeJitValue(PCodeCfg* cfg, |
| jit_function_t f, |
| jit_type_t type, |
| jit_value_t value, |
| PCodeBlock* b, |
| jit_value_t* len = NULL, |
| NABoolean noSave = FALSE) |
| { |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| if (operand != this) |
| return operand->storeJitValue(cfg, f, type, value, b, len, noSave); |
| |
| // |
| // Are we being asked to perform a memcpy? |
| // |
| if (jit_value_get_type(value) == jit_type_void_ptr) { |
| jit_value_t size = |
| ((len) ? *len : jit_value_create_nint_constant(f, jit_type_int,getLen())); |
| |
| if (jitValuePtr_) { |
| assert(jitValueBlock_ != NULL); |
| if (!b->onesVector.testBit(jitValueBlock_->getBlockNum())) |
| jitValuePtr_ = NULL; |
| } |
| |
| if (!jitValuePtr_) { |
| if (isVar() || isNonNativeTemp()) { |
| jit_value_t param = cfg->getJitParams()[stackIndex_]; |
| jitValuePtr_ = jit_insn_add_relative(f, param, offset_); |
| } |
| else { |
| // FIXME: This needs to change. We need to allocate the temp globally |
| // so that references are available everywhere. Best solution is to |
| // pass in temp array and use that. |
| jitValuePtr_ = jit_insn_alloca(f, size); |
| } |
| |
| jitValueBlock_ = b; |
| } |
| |
| // Generate unaligned memcpy instead |
| // jit_insn_memcpy(f, jitValuePtr_, value, size); |
| cfg->genUnalignedMemcpy(f, jitValuePtr_, value, NULL, getLen()); |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) { |
| jitValueBlock_ = NULL; |
| jitValue_ = jitValuePtr_ = NULL; |
| } |
| |
| return; |
| } |
| |
| // |
| // Peforming standard sized moves |
| // |
| |
| if (isVar()) { |
| jit_value_t param = cfg->getJitParams()[stackIndex_]; |
| jit_insn_store_relative(f, param, offset_, value); |
| } |
| else { |
| assert (isTemp()); |
| |
| #if 0 |
| // Just set the value to be the new jitValue |
| // FIX: this is ripe for error :( |
| jitValue_ = value; |
| #endif |
| |
| if (!jitValue_) { |
| jitValue_ = jit_value_create(f, type); |
| } |
| else { |
| // If this block is not dominated by the previous block containing the |
| // first jitValue_, then things like a jitValuePtr_ need to be reset. |
| // Note, the definition of jitValue_ does not need to dominate this block |
| // since when the value is created (as it is above), it is done so upon |
| // entry to the routine (and therefore available everywhere). Addresses |
| // are not, however, and therefore may need to be recalculated. |
| if (jitValuePtr_ && |
| (!b->onesVector.testBit(jitValueBlock_->getBlockNum()))) |
| jitValuePtr_ = NULL; |
| } |
| |
| jit_insn_store(f, jitValue_, value); |
| |
| jitValueBlock_ = b; |
| } |
| |
| // If we are directly told not to save the jit values, don't! |
| if (noSave) { |
| jitValueBlock_ = NULL; |
| jitValue_ = jitValuePtr_ = NULL; |
| } |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| |
| // |
| // IR_insn_branch_if_zero() - generate branch instruction to specified |
| // target IR block *if* the specified 'value' is equal to 0. |
| // |
| // NOTES: |
| // (1) Works regardless of whether 'value' is an 8-bit, 16-bit, |
| // 32-bit, or 64-bit value. |
| // (2) Specified target IR block must have already been created. |
| // (3) This routine only generates the conditional branch. It does *not* |
| // do the "push_back" on the tgt block to place it in the |
| // output "stream". |
| // (4) This routine always creates an IR block for the "if not zero" condition |
| // and does the "push_back" on it as well as setting the "InsertPoint" |
| // to the "if not" IR block. |
| // |
| void PCodeCfg::IR_insn_branch_if_zero( IRBldr_t * Bldr |
| , jit_value_t value |
| , p_IR_block_t * tgt_IR_block |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| DPT0( "VV1000: ", VV_BD, "GOT into IR_insn_branch_if_zero()\n" ); |
| |
| llvm::LLVMContext &LLContxt = Bldr->getContext(); |
| |
| llvm::Function *ExpFn = Bldr->GetInsertBlock()->getParent(); |
| |
| // Create an IR block for the "if not zero" case |
| p_IR_block_t ifNZ_Blk = BasicBlock::Create( LLContxt, "BrIf_NZ_Blk" ); |
| |
| DPT1( "VV1001: ", VV_VD, "ifNZ_Blk = %p\n", ifNZ_Blk ); |
| |
| jit_value_t Zero = ConstantInt::get( value->getType(), 0 ); |
| |
| DPT0( "VV1002: ", VV_VD, |
| "IsZero = Bldr->CreateICmpEQ( value, Zero, 'check0' )\n" ); |
| jit_value_t IsZero = Bldr->CreateICmpEQ( value, Zero, "check0" ); |
| |
| DPT2( "VV1004: ", VV_VD, |
| "Bldr->CreateCondBr( IsZero, *tgt_IR_block = %p, ifNZ_Blk = %p )\n", *tgt_IR_block, ifNZ_Blk ); |
| Bldr->CreateCondBr( IsZero, *tgt_IR_block, ifNZ_Blk ); |
| |
| DPT1( "VV1006: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( ifNZ_Blk = %p )\n", ifNZ_Blk ); |
| ExpFn->getBasicBlockList().push_back( ifNZ_Blk ); |
| |
| DPT1( "VV1008: ", VV_VD, |
| "Bldr->SetInsertPoint( ifNZ_Blk = %p )\n", ifNZ_Blk ); |
| Bldr->SetInsertPoint( ifNZ_Blk ); |
| |
| } |
| |
| // |
| // IR_insn_branch_if_not_zero() - generate branch instruction to specified |
| // target IR block *if* the specified 'value' is NOT equal to 0. |
| // |
| // NOTES: |
| // (1) Works regardless of whether 'value' is an 8-bit, 16-bit, |
| // 32-bit, or 64-bit value. |
| // (2) Specified target IR block must have already been created. |
| // (3) This routine only generates the conditional branch. It does *not* |
| // do the "push_back" on the tgt block to place it in the |
| // output "stream". |
| // (4) This routine always creates an IR block for the "if Zero" condition |
| // and does the "push_back" on it as well as setting the "InsertPoint" |
| // to the "if not" IR block. |
| // |
| void PCodeCfg::IR_insn_branch_if_not_zero( IRBldr_t * Bldr |
| , jit_value_t value |
| , p_IR_block_t * tgt_IR_block |
| ) |
| { |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| DPT0( "VV1100: ", VV_BD, "GOT into IR_insn_branch_if_not_zero()\n" ); |
| |
| llvm::LLVMContext &LLContxt = Bldr->getContext(); |
| |
| llvm::Function *ExpFn = Bldr->GetInsertBlock()->getParent(); |
| |
| // Create an IR block for the "if zero" case |
| p_IR_block_t if_0_Blk = BasicBlock::Create( LLContxt, "BrIfZeroBlk" ); |
| |
| DPT1( "VV1101: ", VV_VD, "if_0_Blk = %p\n", if_0_Blk ); |
| |
| jit_value_t Zero = ConstantInt::get( value->getType(), 0 ); |
| |
| DPT0( "VV1102: ", VV_VD, |
| "IsZero = Bldr->CreateICmpEQ( value, Zero, 'check0' )\n" ); |
| jit_value_t IsZero = Bldr->CreateICmpEQ( value, Zero, "check0" ); |
| |
| DPT2( "VV1104: ", VV_VD, |
| "Bldr->CreateCondBr( IsZero, if_0_Blk = %p, *tgt_IR_block = %p )\n", if_0_Blk, *tgt_IR_block ); |
| Bldr->CreateCondBr( IsZero, if_0_Blk, *tgt_IR_block ); |
| |
| DPT1( "VV1106: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( if_0_Blk = %p )\n", if_0_Blk ); |
| ExpFn->getBasicBlockList().push_back( if_0_Blk ); |
| |
| DPT1( "VV1108: ", VV_VD, |
| "Bldr->SetInsertPoint( if_0_Blk = %p )\n", if_0_Blk ); |
| Bldr->SetInsertPoint( if_0_Blk ); |
| |
| } |
| |
| void PCodeOperand::storeNullJitValueAndBranch( PCodeCfg * cfg |
| , IRBldr_t * Bldr |
| , jit_value_t value |
| , p_IR_block_t tgtLabel |
| , NABoolean forComp |
| , PCodeBlock * b |
| ) |
| { |
| #if NExprDbgLvl >= VV_NO |
| char NExBuf[500]; |
| #endif |
| |
| jit_value_t res = NULL ; |
| |
| CDPT0( "VV1200: ", VV_BD, "GOT into storeNullJitValueAndBranch()\n" ); |
| |
| // Use pCode[2-3] to chk if op2 is NULL |
| // If it is NULL, set output = NULL |
| // and go to next PCode instruction; |
| // Else set output = NOT NULL |
| // and add pCode[7] to pCode ptr |
| |
| // If 'value' is non-zero, then |
| |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| |
| CDPT2( "VV1205: ", VV_BD, "In storeNullJVaBR(): operand=%p, this=%p\n", operand, this ); |
| |
| if (operand != this) |
| return operand->storeNullJitValueAndBranch(cfg, Bldr, value, tgtLabel, |
| forComp, b); |
| |
| //jit_value_t zeroJitVal16=jit_value_create_nint_constant(f, jit_type_short, 0); |
| jit_value_t zeroJitVal16 = ConstantInt::get( cfg->getInt16Ty(), 0 ); |
| |
| //jit_value_t neg1JitVal16=jit_value_create_nint_constant(f, jit_type_short,-1); |
| jit_value_t neg1JitVal16 = ConstantInt::get( cfg->getInt16Ty(), -1 ); |
| |
| llvm::Function *ExpFn = Bldr->GetInsertBlock()->getParent(); |
| |
| // Is src a null bit value or not (doesn't matter) |
| if (TRUE) |
| { |
| llvm::LLVMContext &LLContxt = Bldr->getContext(); |
| p_IR_block_t nullLabel = BasicBlock::Create( LLContxt, "StoreNJ_nullBlk" ); |
| |
| CDPT1( "VV1210: ", VV_BD, "nullLabel = %p\n", nullLabel ); |
| |
| // |
| // NOTE: We don't need a "merge" block because we will either branch |
| // to the tgtLabel or we will use the "nullLabel" block after |
| // we are done with this routine. |
| // |
| CDPT1( "VV1212: ", VV_BD, "In storeNullJitV... Value's Type ID is %d\n", |
| (int) value->getType()->getTypeID() ); |
| |
| // Branch away if source is null. |
| // jit_insn_branch_if(f, value, &nullLabel); |
| cfg->IR_insn_branch_if_not_zero( Bldr, value, &nullLabel ); |
| |
| // At this point, we know 'value' is zero -- indicating a NON-NULL |
| |
| // Is tgt null-indicator just a bit? If so, we must zero that bit to indicate a non-null |
| if (nullBitIndex_ != -1) { |
| UInt8 m = ((UInt8)0x1 << (7 - (nullBitIndex_ & 7))); |
| |
| // Tgt must be a var for it to have a null bit index. |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| |
| CDPT0( "VV1210: ", VV_BD, |
| "param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() )\n" ); |
| jit_value_t param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() ); |
| |
| // jit_value_t mask = jit_value_create_nint_constant(f, jit_type_ubyte, ~m); |
| jit_value_t mask = ConstantInt::get( cfg->getInt8Ty() , ~m ); |
| |
| // jit_value_t nByte = jit_insn_load_relative(f, param, |
| // offset_ + (nullBitIndex_ >> 3), jit_type_ubyte); |
| jit_value_t nByte = cfg->IR_LoadRelativeWithType( Bldr, param, |
| offset_ + (nullBitIndex_ >> 3), cfg->getInt8Ty() ); |
| |
| // Clear the null bit and store the byte (containing the bit) |
| // jit_value_t res = jit_insn_and(f, nByte, mask); |
| |
| CDPT1( "VV1214: ", VV_BD, |
| "res = Bldr->CreateAnd( nByte, mask = %d )\n", ~m ); |
| res = Bldr->CreateAnd( nByte, mask ); |
| |
| // jit_insn_store_relative(f, param, offset_ + (nullBitIndex_ >> 3), res); |
| |
| CDPT0( "VV1217: ", VV_BD, |
| "cfg->IR_StoreRelativeWithType( Bldr, res, param, offset_ + ..., res->getType() )\n"); |
| cfg->IR_StoreRelativeWithType( Bldr, res, |
| param, offset_ + (nullBitIndex_ >> 3), |
| res->getType() ); |
| |
| // Branch to target label |
| // jit_insn_branch(f, targetLabel); |
| |
| CDPT1( "VV1219: ", VV_BD, |
| "Bldr->CreateBr( tgtLabel = %p )\n", tgtLabel ); |
| Bldr->CreateBr( tgtLabel ); |
| |
| CDPT1( "VV1220: ", VV_BD, "In storeNullJitVal: CREATING BRANCH TO tgtLabel at " |
| "( %p )\n", tgtLabel ); |
| |
| // Now handle NULL case. |
| |
| // jit_insn_label(f, &nullLabel); |
| |
| CDPT1( "VV1220: ", VV_BD, |
| "ExpFn->getBasicBlockList().push_back( nullLabel = %p )\n", nullLabel ); |
| ExpFn->getBasicBlockList().push_back( nullLabel ); |
| |
| CDPT1( "VV1222: ", VV_BD, |
| "Bldr->SetInsertPoint( nullLabel = %p )\n", nullLabel ); |
| Bldr->SetInsertPoint( nullLabel ); |
| |
| CDPT1( "VV1223: ", VV_BD, |
| "In storeNullJitVal: Setting Insert Point to nullLabel at %p\n", |
| nullLabel ); |
| |
| // mask = jit_value_create_nint_constant(f, jit_type_ubyte, m); |
| mask = ConstantInt::get( cfg->getInt8Ty() , m ); |
| |
| // nByte = jit_insn_load_relative(f, param, |
| // offset_ + (nullBitIndex_ >> 3), jit_type_ubyte); |
| nByte = cfg->IR_LoadRelativeWithType( Bldr, param, |
| offset_ + (nullBitIndex_ >> 3), cfg->getInt8Ty() ); |
| |
| // Set the null bit and store it back |
| // res = jit_insn_or(f, nByte, mask); |
| |
| CDPT1( "VV1224: ", VV_BD, |
| "res = Bldr->CreateOr( nByte, mask = %d )\n", m ); |
| res = Bldr->CreateOr( nByte, mask ); |
| |
| // jit_insn_store_relative(f, param, offset_ + (nullBitIndex_ >> 3), res); |
| |
| CDPT0( "VV1224: ", VV_BD, |
| "cfg->IR_StoreRelativeWithType( Bldr, res, param, offset_ + ..., res->getType() )\n"); |
| cfg->IR_StoreRelativeWithType( Bldr, res, |
| param, offset_ + (nullBitIndex_ >> 3), |
| res->getType() ); |
| |
| } // End: if (nullBitIndex_ != -1) |
| |
| else { |
| // Tgt is a standard type, so we store a 0 in the null-indicator (to indicate non-null) |
| if (isVar()) { |
| jit_value_t parm1 = cfg->getJitParams()[stackIndex_]; |
| |
| CDPT0( "VV1230: ", VV_BD, |
| "param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() )\n" ); |
| jit_value_t param = Bldr->CreatePointerCast(parm1, cfg->getInt8PtrTy() ); |
| |
| // Store a zero, indicating non-null |
| // jit_insn_store_relative(f, param, offset_, |
| // (forComp ? cfg->getZeroJitVal() : zeroJitVal16)); |
| |
| res = forComp ? cfg->getZeroJitVal() : zeroJitVal16 ; |
| |
| CDPT1( "VV1232: ", VV_BD, "In storeNJ-forComp = %d\n", forComp); |
| CDPT1( "VV1234: ", VV_BD, "In storeNJ-res=%s\n", |
| res==zeroJitVal16 ? "zeroJitVal16" : "cfg->getZeroJitVal()" ); |
| CDPT1( "VV1236: ", VV_BD, "In storeNJ-type WIDTH = %d\n", |
| res->getType()->getIntegerBitWidth() ); |
| |
| CDPT0( "VV1240: ", VV_BD, |
| "cfg->IR_StoreRelativeWithType( Bldr, res, param, offset_, res->getType() )\n"); |
| cfg->IR_StoreRelativeWithType( Bldr, res, param, offset_, res->getType() ); |
| |
| // jit_insn_branch(f, targetLabel); |
| |
| CDPT1( "VV1242: ", VV_BD, |
| "Bldr->CreateBr( tgtLabel = %p )\n", tgtLabel ); |
| Bldr->CreateBr( tgtLabel ); |
| |
| // Now handle NULL case. |
| |
| // jit_insn_label(f, &nullLabel); |
| |
| CDPT1( "VV1244: ", VV_BD, |
| "ExpFn->getBasicBlockList().push_back( nullLabel = %p )\n", nullLabel ); |
| ExpFn->getBasicBlockList().push_back( nullLabel ); |
| |
| CDPT1( "VV1246: ", VV_BD, |
| "Bldr->SetInsertPoint( nullLabel = %p )\n", nullLabel ); |
| Bldr->SetInsertPoint( nullLabel ); |
| |
| // jit_insn_store_relative(f, param, offset_, |
| // (forComp ? cfg->getNeg1JitVal() : neg1JitVal16)); |
| |
| res = forComp ? cfg->getNeg1JitVal() : neg1JitVal16 ; |
| |
| CDPT1( "VV1247: ", VV_BD, "In storeNJ1-forComp = %d\n", forComp); |
| CDPT1( "VV1248: ", VV_BD, "In storeNJ1-res=%s\n", |
| res==neg1JitVal16 ? "neg1JitVal16":"cfg->getNeg1JitVal()"); |
| CDPT1( "VV1249: ", VV_BD, "In storeNJ1-type WIDTH = %d\n", |
| res->getType()->getIntegerBitWidth() ); |
| |
| CDPT0( "VV1250: ", VV_BD, |
| "cfg->IR_StoreRelativeWithType( Bldr, res, param, offset_, res->getType() )\n"); |
| cfg->IR_StoreRelativeWithType( Bldr, res, |
| param, offset_, |
| res->getType() ); |
| |
| } // End: if (isVar()) |
| |
| else { |
| if ( 1 /* forComp ? */) { |
| // storeJitValue(cfg, f, jit_type_int, cfg->getZeroJitVal(), b, NULL); |
| |
| CDPT1( "VV1252: ", VV_BD, "In storeNJ2 ... forComp = %d\n", forComp); |
| CDPT1( "VV1253: ", VV_BD, "In storeNJ2 ... storetype = %s\n", |
| "cfg->getInt32Ty()"); |
| storeJitValue(cfg, Bldr, cfg->getInt32Ty(), cfg->getZeroJitVal(), b, NULL ); |
| |
| // jit_insn_branch(f, targetLabel); |
| |
| CDPT1( "VV1255: ", VV_BD, |
| "Bldr->CreateBr( tgtLabel = %p )\n", tgtLabel ); |
| Bldr->CreateBr( tgtLabel ); |
| |
| // Now handle NULL case. |
| |
| // jit_insn_label(f, &nullLabel); |
| |
| CDPT1( "VV1260: ", VV_BD, |
| "ExpFn->getBasicBlockList().push_back( nullLabel = %p )\n", nullLabel ); |
| ExpFn->getBasicBlockList().push_back( nullLabel ); |
| |
| CDPT1( "VV1261: ", VV_BD, |
| "Bldr->SetInsertPoint( nullLabel = %p )\n", nullLabel ); |
| Bldr->SetInsertPoint( nullLabel ); |
| |
| // storeJitValue(cfg, f, jit_type_int, cfg->getNeg1JitVal(), b, NULL); |
| storeJitValue(cfg, Bldr, cfg->getInt32Ty(), cfg->getNeg1JitVal(), b, NULL ); |
| } |
| #if 0 /* The following OPTIMIZATION (over the above section of code) does NOT always work */ |
| // because sometimes we NEED the call to storeJitValue above even for Temps. |
| // Case in point: Launchpad defect 1328248 |
| else { // forComp == FALSE |
| |
| CDPT1( "VV1262: ", VV_BD, "In storeNJ3 ... forComp = %d\n", forComp); |
| |
| jitValue_ = value; |
| |
| CDPT2( "VV1263: ", VV_BD, |
| "In storeNullJV(): setting jitValue_ in PCodeOp at %p to %p\n", |
| this, jitValue_ ); |
| CDPT1( "VV1264: ", VV_BD, |
| "In storeNJ- jitValue_'s Type ID is %d\n", |
| (int)jitValue_->getType()->getTypeID() ); |
| CDPT2( "VV1264A: ", VV_BD, |
| "In storeNullJV(): setting jitValueBlock_ = %p for PCop = %p\n", |
| b, this ); |
| jitValueBlock_ = b; |
| |
| // jit_insn_branch(f, targetLabel); |
| |
| CDPT1( "VV1265: ", VV_BD, |
| "Bldr->CreateBr( tgtLabel = %p )\n", tgtLabel ); |
| Bldr->CreateBr( tgtLabel ); |
| |
| // jit_insn_label(f, &nullLabel); |
| |
| CDPT1( "VV1267: ", VV_BD, |
| "ExpFn->getBasicBlockList().push_back( nullLabel = %p )\n", nullLabel ); |
| ExpFn->getBasicBlockList().push_back( nullLabel ); |
| |
| CDPT1( "VV1268: ", VV_BD, |
| "Bldr->SetInsertPoint( nullLabel = %p )\n", nullLabel ); |
| Bldr->SetInsertPoint( nullLabel ); |
| |
| } // End: else |
| #endif |
| } // End: else [i.e. (isVar()) == FALSE ] |
| } // End: else [ i.e. (nullBitIndex_ == -1) ] |
| } // End: if (TRUE) |
| } |
| |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| void PCodeOperand::storeNullJitValueAndBranch(PCodeCfg* cfg, |
| jit_function_t f, |
| jit_value_t value, |
| jit_label_t* targetLabel, |
| NABoolean forComp, |
| PCodeBlock* b) |
| { |
| // Get operand in hash table |
| CollIndex i = bvIndex_; |
| PCodeOperand* operand = cfg->getMap()->getFirstValue(&i); |
| if (operand != this) |
| return operand->storeNullJitValueAndBranch(cfg, f, value, targetLabel, |
| forComp, b); |
| |
| jit_label_t nullLabel = jit_label_undefined; |
| |
| jit_value_t zeroJitVal16=jit_value_create_nint_constant(f, jit_type_short, 0); |
| jit_value_t neg1JitVal16=jit_value_create_nint_constant(f, jit_type_short,-1); |
| |
| // Is src a null bit value or not (doesn't matter) |
| if (TRUE) |
| { |
| // Branch away if source is null. |
| jit_insn_branch_if(f, value, &nullLabel); |
| |
| // Is tgt a null bit? |
| if (nullBitIndex_ != -1) { |
| UInt8 m = ((UInt8)0x1 << (7 - (nullBitIndex_ & 7))); |
| |
| // Tgt must be a var for it to have a null bit index. |
| jit_value_t param = cfg->getJitParams()[stackIndex_]; |
| jit_value_t mask = jit_value_create_nint_constant(f, jit_type_ubyte, ~m); |
| jit_value_t nByte = jit_insn_load_relative(f, param, |
| offset_ + (nullBitIndex_ >> 3), jit_type_ubyte); |
| |
| // Clear value and restore. |
| jit_value_t res = jit_insn_and(f, nByte, mask); |
| jit_insn_store_relative(f, param, offset_ + (nullBitIndex_ >> 3), res); |
| |
| // Branch to target label |
| jit_insn_branch(f, targetLabel); |
| |
| // Now handle NULL case. |
| |
| jit_insn_label(f, &nullLabel); |
| |
| mask = jit_value_create_nint_constant(f, jit_type_ubyte, m); |
| nByte = jit_insn_load_relative(f, param, |
| offset_ + (nullBitIndex_ >> 3), jit_type_ubyte); |
| |
| // Set value and restore. |
| res = jit_insn_or(f, nByte, mask); |
| jit_insn_store_relative(f, param, offset_ + (nullBitIndex_ >> 3), res); |
| } |
| else { |
| // Tgt is a standard type |
| if (isVar()) { |
| jit_value_t param = cfg->getJitParams()[stackIndex_]; |
| jit_insn_store_relative(f, param, offset_, |
| (forComp ? cfg->getZeroJitVal() : zeroJitVal16)); |
| jit_insn_branch(f, targetLabel); |
| |
| // Now handle NULL case. |
| |
| jit_insn_label(f, &nullLabel); |
| jit_insn_store_relative(f, param, offset_, |
| (forComp ? cfg->getNeg1JitVal() : neg1JitVal16)); |
| } |
| else { |
| if (forComp) { |
| storeJitValue(cfg, f, jit_type_int, cfg->getZeroJitVal(), b, NULL); |
| jit_insn_branch(f, targetLabel); |
| |
| // Now handle NULL case. |
| |
| jit_insn_label(f, &nullLabel); |
| storeJitValue(cfg, f, jit_type_int, cfg->getNeg1JitVal(), b, NULL); |
| } |
| else { |
| jitValue_ = value; |
| jitValueBlock_ = b; |
| jit_insn_branch(f, targetLabel); |
| jit_insn_label(f, &nullLabel); |
| } |
| } |
| } |
| } |
| } |
| |
| void PCodeCfg::jitProcessFloatExceptionCheck(jit_function_t f, |
| PCodeOperand* fRes, |
| jit_label_t* errorJitLabel, |
| PCodeBlock* block) |
| { |
| jit_value_t temp1, temp2, temp3, temp4; |
| |
| jit_value_t expShift = jit_value_create_nint_constant(f, jit_type_int, 20); |
| jit_value_t expMask = jit_value_create_nint_constant(f, jit_type_int, 0x7ff); |
| |
| jit_value_t fVal = fRes->getJitValue(this, f, jit_type_void_ptr, block); |
| |
| // Get the upper 32-bits of the double |
| temp1 = jit_insn_load_relative(f, fVal, 4, jit_type_uint); |
| |
| // Shift the load over so that the last 12 bits are in the lower |
| temp2 = jit_insn_ushr(f, temp1, expShift); |
| |
| // Mask out exponent and compare to see if 11-bit exponent is all set. |
| temp3 = jit_insn_and(f, temp2, expMask); |
| temp4 = jit_insn_eq(f, temp3, expMask); |
| |
| jit_insn_branch_if(f, temp4, errorJitLabel); |
| } |
| |
| #if 0 |
| |
| NABoolean PCodeCfg::jitProcessPredicate(PCodeInst* comp, |
| jit_value_t compJitVal, |
| jit_function_t f) |
| { |
| if (comp->next && comp->next->isAnyLogicalBranch()) |
| { |
| PCodeInst* branch = comp->next; |
| |
| PCodeOperand* compTgt = comp->getWOps()[0]; |
| PCodeOperand* branchSrc = branch->getROps()[0]; |
| PCodeOperand* branchTgt = branch->getWOps()[0]; |
| |
| PCodeBlock* block = comp->block; |
| |
| NABoolean srcLive = FALSE, tgtLive = FALSE; |
| |
| if (branchSrc->getBvIndex() == compTgt->getBvIndex()) { |
| // Is source or target live after branch? |
| srcLive = branchSrc->isVar() || block->isOperandLiveInSuccs(branchSrc); |
| tgtLive = branchTgt->isVar() || block->isOperandLiveInSuccs(branchTgt); |
| |
| if (srcLive) |
| compTgt->storeJitValue(this, f, jit_type_int, compJitVal, block); |
| |
| if (tgtLive) |
| branchTgt->storeJitValue(this, f, jit_type_int, compJitVal, block); |
| |
| if ((branch->getOpcode() == PCIT::BRANCH_OR) || |
| (branch->getOpcode() == PCIT::BRANCH_OR_CNT)) { |
| jit_insn_branch(f, block->getTargetBlock()->getJitLabel()); |
| else |
| jit_insn_branch(f, block->getFallThroughBlock()->getJitLabel()); |
| } |
| } |
| } |
| else if (comp->next && (comp->next->getOpcode() == PCIT::MOVE_MBIN32S)) |
| { |
| PCodeInst* move = comp->next; |
| |
| PCodeOperand* compTgt = comp->getWOps()[0]; |
| PCodeOperand* moveSrc = move->getROps()[0]; |
| |
| if (compTgt->getBvIndex() == moveSrc->getBvIndex()) { |
| // A RETURN is guaranteed to following a MOVE_MBIN32S (verify w/ assert) |
| assert (move->next && (move->next->getOpcode() == PCIT::RETURN)); |
| } |
| } |
| } |
| |
| #endif |
| |
| NABoolean PCodeCfg::jitProcessPredicate(PCodeInst* comp, |
| jit_function_t f, |
| jit_label_t* falseLabel, |
| jit_label_t* trueLabel, |
| NABoolean isFirstBlockTrue) |
| { |
| CollIndex i; |
| |
| // |
| // Called when generating the TRUE and FALSE blocks first for certain |
| // comparisons. Rather than check the result of the comparison twice (one |
| // for the COMP and another for a subsequent BRANCH), we attempt to do it all |
| // at once. |
| // |
| // A boolean called isFirstBlockTrue passed in to tell us if the 1st block |
| // to generate is the "true" block or not. |
| // |
| |
| if (comp->next && comp->next->isAnyLogicalBranch()) |
| { |
| PCodeInst* branch = comp->next; |
| |
| PCodeOperand* compTgt = comp->getWOps()[0]; |
| PCodeOperand* branchSrc = branch->getROps()[0]; |
| PCodeOperand* branchTgt = branch->getWOps()[0]; |
| |
| PCodeBlock* block = comp->block; |
| |
| NABoolean srcLive = FALSE, tgtLive = FALSE; |
| |
| if (branchSrc->getBvIndex() == compTgt->getBvIndex()) { |
| // Is source or target live after branch? |
| srcLive = branchSrc->isVar() || block->isOperandLiveInSuccs(branchSrc); |
| tgtLive = branchTgt->isVar() || block->isOperandLiveInSuccs(branchTgt); |
| |
| // Dump out blocks now (either TRUE followed by FALSE, or vice-versa) |
| // Use for loop to simplify code (i.e. reduce duplication of code) in |
| // laying out the blocks one way or the other. |
| |
| for (i=0; i < 2; i++) |
| { |
| if ((isFirstBlockTrue && (i==0)) || |
| (!isFirstBlockTrue && (i==1))) |
| { |
| jit_insn_label(f, trueLabel); |
| |
| // Dump true block first |
| if (srcLive) |
| compTgt->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| |
| if (tgtLive) |
| branchTgt->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| |
| if ((branch->getOpcode() == PCIT::BRANCH_OR) || |
| (branch->getOpcode() == PCIT::BRANCH_OR_CNT)) |
| jit_insn_branch(f, block->getTargetBlock()->getJitLabel()); |
| else |
| jit_insn_branch(f, block->getFallThroughBlock()->getJitLabel()); |
| } |
| |
| if ((!isFirstBlockTrue && (i==0)) || |
| (isFirstBlockTrue && (i==1))) |
| { |
| // Dump false block next - layout false block label first. |
| jit_insn_label(f, falseLabel); |
| |
| if (srcLive) |
| compTgt->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| |
| if (tgtLive) |
| branchTgt->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| |
| if ((branch->getOpcode() == PCIT::BRANCH_AND) || |
| (branch->getOpcode() == PCIT::BRANCH_AND_CNT)) |
| jit_insn_branch(f, block->getTargetBlock()->getJitLabel()); |
| else |
| jit_insn_branch(f, block->getFallThroughBlock()->getJitLabel()); |
| } |
| } |
| |
| return TRUE; |
| } |
| } |
| else if (comp->next && (comp->next->getOpcode() == PCIT::MOVE_MBIN32S)) |
| { |
| PCodeInst* move = comp->next; |
| |
| PCodeOperand* compTgt = comp->getWOps()[0]; |
| PCodeOperand* moveSrc = move->getROps()[0]; |
| |
| if (compTgt->getBvIndex() == moveSrc->getBvIndex()) { |
| // A RETURN is guaranteed to following a MOVE_MBIN32S (verify w/ assert) |
| assert (move->next && (move->next->getOpcode() == PCIT::RETURN)); |
| |
| if (isFirstBlockTrue) { |
| jit_insn_label(f, trueLabel); |
| jit_insn_return(f, tJitVal_); |
| |
| // False block next - add label first. |
| jit_insn_label(f, falseLabel); |
| jit_insn_return(f, fJitVal_); |
| } |
| else { |
| jit_insn_label(f, falseLabel); |
| jit_insn_return(f, fJitVal_); |
| |
| // True block next - add label first. |
| jit_insn_label(f, trueLabel); |
| jit_insn_return(f, tJitVal_); |
| } |
| |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |
| #if 1 /* NA_LINUX_LLVMJIT */ |
| |
| void PCodeCfg::layoutNativeCode() |
| { |
| static pthread_mutex_t Our_LLVM_mutex = PTHREAD_MUTEX_INITIALIZER; |
| |
| // List of signal numbers for which LLVM establishes its own signal handlers |
| static const int SaveSigs[] = { |
| SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGFPE, |
| SIGSEGV, SIGUSR2, SIGPIPE, SIGTERM, SIGXFSZ |
| }; |
| static const int NumSaveSigs = sizeof(SaveSigs) / sizeof(SaveSigs[0]); |
| |
| static THREAD_P struct { |
| struct sigaction SigAct ; |
| } SavedSigInfo[ NumSaveSigs ]; |
| |
| static struct { |
| struct sigaction SigAct ; |
| } SavedLLVMhandlers[ NumSaveSigs ]; |
| |
| static NABoolean LLVMhandlersSaved = FALSE ; |
| |
| |
| #if NExprDbgLvl > VV_NO |
| char NExBuf[500]; |
| #endif |
| Int32 PCI_count = 0 ; //Count of number of PCODE instructions translated. |
| |
| expr_->setPCodeNative(FALSE); // For now, assume no native code generated. |
| |
| NABoolean debug = FALSE; |
| if (getenv("NATIVE_EXPR_DEBUG")) |
| debug = TRUE; |
| |
| PCodeBinary* pCode = expr_->getPCodeBinary(); |
| |
| NExTempsList_ = new(heap_) NExTEMPSLIST(heap_); |
| |
| |
| // First see if this graph can be compiled natively |
| if ( ! canGenerateNativeExpr() ) |
| { |
| delete NExTempsList_ ; |
| NExTempsList_ = NULL ; |
| expr_->setEvalPtr( (ex_expr::evalPtrType)( (CollIndex) 0 ) );//Ensure NULL! |
| return; |
| } |
| |
| #if NExprDbgLvl >= VV_I0 |
| struct rusage begTime; |
| |
| if ( NExprDbgLvl_ >= VV_I0 ) |
| { |
| std::cout << std::flush ; // Flush anything in the data buffer |
| (void) getrusage( RUSAGE_THREAD, &begTime ); |
| |
| char* StTime = ctime((const time_t*)&begTime.ru_utime.tv_sec); |
| Int32 StTimeLn = strlen(StTime); |
| StTime[StTimeLn-1] = ' '; |
| |
| DPT2( "VV90000: ", VV_I3, |
| "STARTING layoutNativeCode() at %s : Microseconds: %d\n", |
| StTime, (int) begTime.ru_utime.tv_usec ); |
| |
| if ( NExprDbgLvl_ >= VV_I1 && |
| NExDbgInfoPtr_->getNExStmtPrinted() == FALSE ) |
| { |
| NExDbgInfoPtr_->setNExStmtPrinted( TRUE ); |
| |
| if ( NExDbgInfoPtr_->getNExStmtSrc() ) |
| { |
| NExLog( "==Orig. SQL Stmt:\n" ); |
| NExLog( NExDbgInfoPtr_->getNExStmtSrc() ); |
| NExLog( "\n==\n" ); |
| } |
| } |
| std::cout << std::flush ; // Flush anything in the data buffer |
| } |
| #endif // NExprDbgLvl >= VV_I0 |
| |
| Int32 opc = PCIT::Op_END; |
| CollIndex i, j, PCBlkIndex; |
| |
| Int32 skipInst = 0; |
| |
| // First compute the dominator tree |
| computeDomTree(); |
| |
| // |
| // Since the LLVM library is not thread-safe, we get a mutex at this point. |
| // If the mutex is not immediately available, then another thread is using |
| // LLVM right now, so we just fall back to using PCODE and not try to |
| // generate a Native Expression right now. |
| // |
| int tryVal = pthread_mutex_trylock( &Our_LLVM_mutex ); |
| if ( tryVal ) |
| { |
| delete NExTempsList_ ; |
| NExTempsList_ = NULL ; |
| expr_->setEvalPtr( (ex_expr::evalPtrType)( (CollIndex) 0 ) );//Ensure NULL! |
| |
| #if NExprDbgLvl >= VV_I2 |
| if ( NExprDbgLvl_ >= VV_I2 ) { |
| DPT0( "VV90000A: ", VV_XD, "Not translating to native code - mutex locked.\n"); |
| } |
| #endif |
| return; |
| } |
| |
| // |
| // Now that we have the mutex, save the current signal handlers for signals |
| // for which LLVM has handlers. Also, if we have previously saved LLVM's |
| // sigaction handlers, restore them before we go back into LLVM code. |
| // |
| for (Int32 ii = 0; ii < NumSaveSigs ; ii++ ) |
| { |
| Int32 ret = sigaction( SaveSigs[ii], |
| ( LLVMhandlersSaved ) ? |
| &(SavedLLVMhandlers[ii].SigAct) : (const struct sigaction *)NULL, |
| &(SavedSigInfo[ii].SigAct) ) ; |
| assert( ret == 0 ); |
| } |
| |
| llvm::InitializeNativeTarget(); |
| llvm::LLVMContext &LLContxt = llvm::getGlobalContext(); |
| |
| // Create context to hold the LLVM JIT's primary state |
| |
| // Make the module, which holds all the code. |
| llvm::Module * TheModule = new llvm::Module("ExpressionJit", LLContxt); |
| |
| llvm::IRBuilder<> * Bldr = new llvm::IRBuilder<>( LLContxt ); |
| |
| std::map<std::string, Value*> NamedValues; |
| |
| |
| // Create the "ExecutionEngine" |
| std::string ErrStr; |
| llvm::TargetOptions target_opts; |
| target_opts.PositionIndependentExecutable = 1; |
| |
| // |
| // NOTE: By specifying "x86-64" in the call to setMArch() below and |
| // specifying only the generic 64-bit attributes and *not* specifying |
| // any chip-specific attributes in the call to setMAttrs() below, |
| // we are telling the JIT compiler to generate machine code for a |
| // generic x86-64 chip rather than letting it default to generating |
| // machine code for the specific chip that the SQL Compiler happens |
| // to be running on at the moment. |
| // |
| std::vector<std::string> MAttrs; // Machine Architecture attributes |
| MAttrs.push_back("64bit-mode"); |
| |
| llvm::ExecutionEngine* TheExecutionEngine = |
| EngineBuilder(TheModule).setErrorStr(&ErrStr).setMArch("x86-64").setMAttrs(MAttrs).setTargetOptions(target_opts).setRelocationModel(llvm::Reloc::PIC_).setOptLevel(CodeGenOpt::Default).create(); |
| if ( !TheExecutionEngine ) |
| { |
| std::cout << ErrStr << std::flush; |
| printf("EXITING FROM layoutNativeCode() -could not create function !!\n"); |
| std::cout << std::flush ; // Flush anything in the data buffer |
| |
| delete Bldr ; |
| |
| // |
| // Restore signal handlers to what they were on entry. |
| // NOTE: We do NOT try to save the LLVM handlers when going through this |
| // code the first time because LLVM has *not* set them up yet. |
| // |
| for (Int32 ii = 0; ii < NumSaveSigs ; ii++ ) |
| { |
| Int32 ret = sigaction( SaveSigs[ii], &(SavedSigInfo[ii].SigAct), |
| (struct sigaction *)NULL); |
| assert( ret == 0 ); |
| } |
| pthread_mutex_unlock( &Our_LLVM_mutex ); // Other threads could use LLVM now |
| |
| delete NExTempsList_ ; |
| NExTempsList_ = NULL ; |
| expr_->setEvalPtr( (ex_expr::evalPtrType)( (CollIndex) 0 ) );//Ensure NULL! |
| return ; |
| } |
| |
| // Initialize various jit_type_t (llvm::Type) pointers in PCodeCfg object |
| // for easy reference later. |
| // |
| int1PtrTy_ = llvm::Type::getInt1PtrTy(LLContxt); // Used like old JIT's void ptr |
| int8Ty_ = llvm::Type::getInt8Ty(LLContxt); |
| int16Ty_ = llvm::Type::getInt16Ty(LLContxt); |
| int32Ty_ = llvm::Type::getInt32Ty(LLContxt); |
| int64Ty_ = llvm::Type::getInt64Ty(LLContxt); |
| int8PtrTy_ = llvm::Type::getInt8PtrTy(LLContxt); |
| int16PtrTy_ = llvm::Type::getInt16PtrTy(LLContxt); |
| int32PtrTy_ = llvm::Type::getInt32PtrTy(LLContxt); |
| int64PtrTy_ = llvm::Type::getInt64PtrTy(LLContxt); |
| floatPtrTy_ = llvm::Type::getFloatPtrTy(LLContxt); |
| |
| DPT3( "VV90000a: ", VV_VD, |
| "int1PtrTy_ = %p, int8Ty_ = %p, int16Ty_ = %p\n", int1PtrTy_ , int8Ty_ , int16Ty_ ); |
| |
| DPT2( "VV90000b: ", VV_VD, |
| "int32Ty_ = %p, int64Ty_ = %p\n", int32Ty_ , int64Ty_ ); |
| |
| DPT3( "VV90000c: ", VV_VD, |
| "int8PtrTy_ = %p, int16PtrTy_ = %p, int32PtrTy_ = %p\n", int8PtrTy_ , int16PtrTy_ , int32PtrTy_ ); |
| |
| DPT2( "VV90000d: ", VV_VD, |
| "int64PtrTy_ = %p, floatPtrTy_ = %p\n", int64PtrTy_ , floatPtrTy_ ); |
| |
| /************ KEEP IN COMMENTS FOR NOW -- MAY NEED TO PORT THESE IN THE FUTURE |
| // Create commonly referenced constants |
| JitVal_1_ = jit_value_create_nint_constant(f, jit_type_int, 1); |
| zeroJitVal_ = jit_value_create_nint_constant(f, jit_type_int, 0); |
| neg1JitVal_ = jit_value_create_nint_constant(f, jit_type_int, -1); |
| jit_value_t zeroJitVal16=jit_value_create_nint_constant(f, jit_type_short, 0); |
| jit_value_t neg1JitVal16=jit_value_create_nint_constant(f, jit_type_short,-1); |
| padJitVal = jit_value_create_nint_constant(f, jit_type_ubyte, ' '); |
| jit_value_t shiftRVal = jit_value_create_nint_constant(f, jit_type_int, 31); |
| okJitVal_ = jit_value_create_nint_constant(f, jit_type_int,ex_expr::EXPR_OK); |
| tJitVal_ = jit_value_create_nint_constant(f, jit_type_int,ex_expr::EXPR_TRUE); |
| fJitVal_ = jit_value_create_nint_constant(f,jit_type_int,ex_expr::EXPR_FALSE); |
| eJitVal = jit_value_create_nint_constant(f,jit_type_int,ex_expr::EXPR_ERROR); |
| ************ KEEP IN COMMENTS FOR NOW */ |
| |
| // Create commonly referenced constants |
| IR_Const_1_ = ConstantInt::get( int32Ty_ , 1 ); |
| IR_Const_0_ = ConstantInt::get( int32Ty_ , 0 ); |
| IR_Const_neg1_ = ConstantInt::get( int32Ty_ , -1 ); |
| IR_Const_16bit_0_ = ConstantInt::get( int16Ty_ , 0 ); |
| IR_Const_64bit_0_ = ConstantInt::get( int64Ty_ , 0 ); |
| |
| jit_value_t IR_Const_pad = ConstantInt::get( int8Ty_, ' ' ); |
| |
| IR_Const_OK_ = ConstantInt::get( int32Ty_ , ex_expr::EXPR_OK ); |
| IR_Const_TRUE_ = ConstantInt::get( int32Ty_ , ex_expr::EXPR_TRUE ); |
| IR_Const_FALSE_ = ConstantInt::get( int32Ty_ , ex_expr::EXPR_FALSE ); |
| IR_Const_ERR_ = ConstantInt::get( int32Ty_ , ex_expr::EXPR_ERROR ); |
| |
| pGlobTab_Val_ = NamedValues[ "pGlobTab" ] ; |
| atp1_Val_ = NamedValues[ "atp1" ] ; |
| atp2_Val_ = NamedValues[ "atp2" ] ; |
| ex_expr_p_Val_ = NamedValues[ "ex_expr_p" ] ; |
| |
| // Build the function signature. |
| // Create an "expression" function with 4 parameters |
| // and which returns an Int32 [Actually it returns an enum exp_return_type ] |
| // |
| // NOTE: The 4 parameters (eventually) passed to the function |
| // at runtime will be: |
| // |
| // param[0] = nativeGlobTable* pGlobTab |
| // param[1] = atp_struct* atp1 |
| // param[2] = atp_struct* atp2 |
| // param[3] = ex_expr * ex_expr_ptr [Used to get ptrs to |
| // Constants and Temps] |
| |
| // NOTE: We declare all 4 arguments as (char *) [i.e. int8PtrTy_ ] |
| // because otherwise we would have to cast them to Int8Ptr before |
| // we use them since the first thing we want to do with them is to |
| // add some *byte* offset. In other words, it is just plain easier |
| // to declare them as Int8Ptr, add the byte offset, and then cast |
| // them to be the kind of pointer we really want them to be. |
| // |
| std::vector<Type*> args(4, int1PtrTy_ ); // Lie! Say they are "void" ptrs |
| FunctionType* functype = FunctionType::get( int32Ty_, |
| args, false); |
| |
| // Now that we have the function signature (i.e. functype), we |
| // can tell LLVM to create the "function". |
| // |
| llvm::Function * ExpFn = llvm::Function::Create(functype, |
| llvm::Function::ExternalLinkage, |
| "testExpr", TheModule); |
| |
| // Give the parameters names! |
| std::vector<std::string> Args; |
| Args.push_back("pGlobTab"); |
| Args.push_back("atp1"); |
| Args.push_back("atp2"); |
| Args.push_back("ex_expr_p"); |
| |
| // |
| // Loop through the function arguments (the function type built above |
| // says there are 4 args) and create entries in the NamedValues |
| // array saying that "pGlobTab" has the value that was passed to the |
| // first arg and "atp1" has the value passed to the second arg, etc. |
| // |
| unsigned Idx = 0; |
| for(llvm::Function::arg_iterator AI = ExpFn->arg_begin(); |
| Idx != Args.size(); ++AI, ++Idx) |
| { |
| AI->setName(Args[Idx]); |
| NamedValues[Args[Idx]] = AI; |
| } |
| |
| // Create a single IR block to hold instructions |
| p_IR_block_t IRBlk = BasicBlock::Create(LLContxt, "entryBlk", ExpFn); |
| |
| DPT1( "VV90001: ", VV_VD, |
| "Bldr->SetInsertPoint( IRBlk = %p )\n", IRBlk ); |
| Bldr->SetInsertPoint(IRBlk); |
| |
| jit_value_t globTableJitVal = NamedValues[Args[0]]; |
| |
| // Allocate incoming parameters |
| DPT1( "VV90002: ", VV_XD, |
| "SIZING jitParams_[] to array of size 4+pCode[0] == %d\n", |
| 4+pCode[0] ); |
| |
| jitParams_ = (jit_value_t *) new(heap_) jit_value_t[4 + pCode[0]]; |
| |
| jitParams_[0] = globTableJitVal ; |
| |
| // Generate code for getting tupp pointers |
| // |
| // 1. Get atp pointer (p) passed in |
| // 2. Add bytes to get to tuple we care about |
| // off = &(tempAtp->getTupp(atpIndex)) - (tempAtp) |
| // temp1 = param[atp] + off; |
| // 3. Dereference pointer to get tupp_descriptor pointer |
| // temp2 = load(temp1); |
| // 4. Add bytes to get to dataTuple |
| // off = &(tempTuppDesc.getTupleAddress() |
| |
| atp_struct tempAtp; |
| tupp tempTupp; |
| tupp_descriptor tempTuppDesc; |
| ex_expr Ex_Expr; |
| |
| for (i=0, j=1; i < (CollIndex)pCode[0]; i++, j+=2) |
| { |
| Int64 off1 = 0, off2 = 0; |
| |
| DPT3( "VV90004: ", VV_XD, |
| "INITIALIZING jitParams_[4+i == %d] where j=%d, pCode[0] = %d\n", |
| 4+i, j, pCode[0] ); |
| |
| // First get the atp we care about |
| DPT2( "VV90006: ", VV_XD, |
| "SETTING t1 to NamedValues[ Args[ 1 + pCode[j] ] ] " |
| "where j=%d and pCode[j]=%d\n", j, pCode[j] ); |
| |
| jit_value_t t1 = NamedValues[ Args[ 1 + pCode[j] ] ] ; |
| |
| // Now, at runtime, t1 will point to the atp we care about. |
| // Well, except that t1 is of type "Pointer to 64-bit Int". |
| |
| // So, now we get the tupp descriptor pointer we care about. |
| // We do that by first getting a ptr to the tuppArray entry within the atp_struct |
| |
| DPT1( "VV90008: ", VV_XD, |
| "Passing pCode[j+1] = %d to getTuppForNativeExpr()\n", pCode[j+1] ); |
| off1 = |
| (char*)(&(tempAtp.getTuppForNativeExpr(pCode[j+1]))) - (char*)(&tempAtp); |
| |
| DPT0( "VV90010: ", VV_VD, |
| "Int8p_t1 = Bldr->CreatePointerCast(t1, int8PtrTy_ )\n"); |
| jit_value_t Int8p_t1 = Bldr->CreatePointerCast(t1, int8PtrTy_ ); |
| |
| DPT1( "VV90012: ", VV_VD, |
| "V_tuppArr = IR_LoadRelativeWithType( Bldr, Int8p_t1, off1=%ld, int8PtrTy_ )\n", off1 ); |
| jit_value_t V_tuppArr = IR_LoadRelativeWithType( Bldr, Int8p_t1, off1, int8PtrTy_ ); |
| |
| off2 = ((char *)&(tempTuppDesc.tupleAddress_)) - (char *)(&tempTuppDesc); |
| jit_value_t t3 = IR_LoadRelativeWithType( Bldr, V_tuppArr, off2, int8PtrTy_ ); |
| |
| DPT2( "VV90013: ", VV_XD, |
| "SETTING jitParams_[%d] = rtnval from IR_LoadRelativeWithType(...,V_tuppArr, %ld, ...)\n", |
| 4+i, off2 ); |
| jitParams_[4+i] = t3; |
| |
| } |
| |
| // |
| // Allocate incoming constant pointer (needed for strings and floats). |
| // |
| // Do the same for the temps array pointer. This array is used to store to |
| // those temps which usually don't fit within a native container - e.g. |
| // strings and bignums. |
| // |
| Int64 ConstantsOff = ((char *)&(Ex_Expr.constantsArea_)) - (char *)(&Ex_Expr); |
| |
| DPT1( "VV90013: ", VV_VD, "SET ConstantsOff to %ld\n", ConstantsOff); |
| |
| jit_value_t exprJitVal = NamedValues[ Args[3] ] ; |
| |
| DPT0( "VV90020: ", VV_VD, |
| "jitParams_[1] = IR_LoadRelativeWithType( Bldr, exprJitVal, ConstantsOff, int8PtrTy_ )\n" ); |
| jitParams_[1] = IR_LoadRelativeWithType( Bldr, exprJitVal, |
| ConstantsOff, int8PtrTy_ ); |
| |
| Int64 TempsOff = ((char *)&(Ex_Expr.tempsArea_)) - (char *)(&Ex_Expr); |
| |
| DPT1( "VV90022: ", VV_VD, |
| "jitParams_[2] = IR_LoadRelativeWithType( Bldr, exprJitVal, TempsOff = %ld, int8PtrTy_ )\n", TempsOff); |
| jitParams_[2] = IR_LoadRelativeWithType( Bldr, exprJitVal, |
| TempsOff, int8PtrTy_ ); |
| |
| // Allocate and initialize opData array for use with CLAUSE_EVAL instructions |
| PCodeOperand * opData[(3*ex_clause::MAX_OPERANDS)]; |
| PCodeOperand** opDataNulls = &(opData[0]); |
| PCodeOperand** opDataVals = &(opData[2*ex_clause::MAX_OPERANDS]); |
| str_pad((char*)opData, (3*ex_clause::MAX_OPERANDS)*sizeof(PCodeOperand*), 0); |
| |
| // Allocate pointers to global defs available at runtime. Note, if they are |
| // not referenced by the pcode graph, these loads will be deleted by the jit. |
| |
| // ZZZZ FIX THIS when we add support for something that needs 'nullTable' |
| // DBG_C("VV90030: Bldr->CreateLoad(pGlobTab_Val_)\n"); |
| // DBG_C("VV90031: Bldr->CreateExtractValue(Bldr->CreateLoad(pGlobTab_Val_),0)\n"); |
| // jit_value_t *nullTable = Bldr->CreateExtractValue(Bldr->CreateLoad(pGlobTab_Val_),0); |
| |
| // Allocate all Temps that will be needed! |
| // NOTE: We do this *before* we start creating the native instructions |
| // because otherwise LLVM's JIT Compiler can end up complaining that |
| // some predecessor paths to an IR block allocate the variable while |
| // other predecessor paths to the block don't allocate it. |
| |
| DPT1( "VV90034: ", VV_XD, "After CanGEN, NExTempsList_->entries()=%d\n", |
| NExTempsList_->entries() ); |
| for ( Int32 tli = 0 ; tli < NExTempsList_->entries() ; tli++ ) |
| { |
| NExTempListEntry * tliEntry = (*NExTempsList_)[tli] ; |
| |
| PCIT::AddressingMode OprTyp = tliEntry->getOprTyp() ; |
| PCodeOperand * Oper = tliEntry->getPCOp() ; |
| Int32 Num = tliEntry->getNum() ; |
| |
| DPT3( "VV90035: ", VV_XD, |
| "Oper->allocJitValue( this, Bldr, OprTyp = %d, Len = %d, Num = %d )\n", |
| (Int32)OprTyp, Oper->getLen(), Num ); |
| Oper->allocJitValue( this, Bldr, OprTyp, Oper->getLen(), Num ) ; |
| } |
| delete NExTempsList_ ; // We are done with this, so free it! |
| NExTempsList_ = NULL ; |
| |
| // NOW CREATE THE NATIVE INSTRUCTIONS |
| |
| // Create the list of pcode basic blocks in physical layout order |
| BLOCKLIST physBlockList(heap_); |
| |
| createPhysList(physBlockList); |
| |
| // First create LLVM BasicBlocks objects and keep track of them. |
| // We want one LLVM BasicBlock to start each physBlock. |
| // Depending on the instructions in the block, additonal BasicBlocks |
| // may get created later, but that's all right. We just need |
| // some initial ones so we can generate branches to them when |
| // we encounter a PCODE instruction that branches to a physBlock |
| // |
| |
| NABoolean justGeneratedRET = FALSE; |
| NABoolean justHandledUnconditionBranch = FALSE; |
| |
| for ( PCBlkIndex=0; |
| (PCBlkIndex < physBlockList.entries()) && !getJitFailureSeen(); |
| PCBlkIndex++ ) |
| { |
| PCodeBlock* PCBlk = physBlockList[PCBlkIndex]; |
| |
| p_IR_block_t * IR_Blk_Label = PCBlk->getJitBlkLbl(); |
| |
| * IR_Blk_Label = BasicBlock::Create( LLContxt, "physBlk" ); |
| |
| DPT2( "VV90040: ", VV_XD, |
| "In First Loop: Created BB AT ( %p ) for PCBlk = %p\n", |
| *IR_Blk_Label, PCBlk ); |
| |
| if ( * IR_Blk_Label == IR_block_undefined ) |
| setJitFailureSeen(); |
| } |
| |
| // Branch from the initial IR block to the first IR block with a label. |
| // Note: The 'SetInsertPoint' will be done the first time through the |
| // following loop ... after the IR block gets push_back() called on it. |
| |
| DPT1( "VV90050: ", VV_XD, |
| "Bldr->CreateBr( *(physBlockList[0]->getJitBlkLbl()) = %p )\n", *(physBlockList[0]->getJitBlkLbl()) ); |
| Bldr->CreateBr( *(physBlockList[0]->getJitBlkLbl()) ); |
| |
| // Loop through each pcode block, generating instructions on a per block basis. |
| // We stop immediately if a failure was seen during code gen. |
| |
| DPT1( "VV90052: ", VV_XD, |
| "Starting loop creating one BLOCK at a time, with BLK COUNT=%d\n", |
| physBlockList.entries() ); |
| DPT1( "VV90054: ", VV_VD, "getJitFailureSeen() == %d \n", |
| (int)getJitFailureSeen() ); |
| |
| for (PCBlkIndex=0; |
| (PCBlkIndex < physBlockList.entries()) && !getJitFailureSeen(); |
| PCBlkIndex++) |
| { |
| // Must reset these flags for each PCode Block |
| justGeneratedRET = FALSE; |
| justHandledUnconditionBranch = FALSE; |
| |
| DPT0( "VV90056: ", VV_VD, "Top of loop creating one BLOCK at a time\n"); |
| |
| PCodeBlock* PCBlk = physBlockList[PCBlkIndex]; |
| |
| if ( *(PCBlk->getJitBlkLbl()) != NULL ) |
| { |
| // Insert the IR block into the function and set the |
| // insertion point to start putting instructions |
| // into this IR block. |
| p_IR_block_t IR_Blk_Ptr = *( PCBlk->getJitBlkLbl() ); |
| |
| DPT1( "VV90060: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( IR_Blk_Ptr= %p )\n", IR_Blk_Ptr ); |
| ExpFn->getBasicBlockList().push_back( IR_Blk_Ptr ); |
| |
| DPT1( "VV90062: ", VV_VD, |
| "Bldr->SetInsertPoint( IR_Blk_Ptr = %p )\n", IR_Blk_Ptr ); |
| Bldr->SetInsertPoint( IR_Blk_Ptr ); |
| } |
| |
| FOREACH_INST_IN_BLOCK(PCBlk, PCInst) |
| { |
| PCI_count++ ; |
| |
| DPT0( "VV90100: ", VV_VD, |
| "In Main Loop creating one INSTRUCTION at a time\n"); |
| DPT2( "VV90102: ", VV_XD, |
| "In Main Loop: PCInst at %p, PCInst->next = %p \n", |
| PCInst, PCInst->next ); |
| #if NExprDbgLvl >= VV_VD |
| if ( PCInst->next ) |
| DPT2( "VV90103: ", VV_XD, "In Main Loop: next at %p has opc == %d\n", |
| PCInst->next , (int) PCInst->next->getOpcode()); |
| #endif |
| |
| // If a failure occurred, stop translation immediately. |
| if (getJitFailureSeen()) |
| { |
| DPT0( "VV90105: ", VV_XD, "getJitFailureSeen() returned FAILURE\n"); |
| break; |
| } |
| |
| // Sometimes native code is generated for multiple pcode instructions in |
| // one pass, and so "skipped" instructions don't need to be processed. |
| if (skipInst > 0) |
| { |
| DPT0( "VV90107: ", VV_XD, |
| "skipInst is > 0 so we are doing a 'continue'\n"); |
| skipInst--; |
| continue; |
| } |
| // |
| // NOTE: The code after the end of the FOREACH_INST_IN_BLOCK loop |
| // depends on doing the skipInst check and 'continue' above |
| // *BEFORE* changing the value of the variable 'opc'. |
| // |
| |
| opc = PCInst->getOpcode(); |
| |
| DPT2( "VV90200: ", VV_I1, "Found opc = %d %s\n", (int) opc, NatExprName(opc) ); |
| |
| DPT2( "VV90201: ", VV_XD, "PCInst at %p, PCInst->next = %p\n", |
| PCInst, PCInst->next ); |
| // |
| // LLVM's JIT Compiler gets confused if we generate two RET |
| // instructions back-to-back (within the same IR block.) |
| // So, here we explicitly *NOT* generate any code for a PCIT::RETURN |
| // if the last instruction we generated was a RET instruction. |
| // |
| if ( opc != PCIT::RETURN ) |
| justGeneratedRET = FALSE; |
| |
| if ( justGeneratedRET == FALSE ) |
| switch (opc) |
| { |
| case PCIT::MOVE_MATTR5_MATTR5: |
| { |
| PCodeOperand *src1, *res ; |
| jit_value_t src1JitVal, resJitVal, vcLenJitVal ; |
| jit_type_t src1IRtype, resIRtype, vcType ; |
| |
| src1 = PCInst->getROps()[0]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| if (src1->getVcIndicatorLen() == 2) { |
| //// vcType = jit_type_ushort; |
| //// vcLenJitVal = jit_value_create_nint_constant(f, jit_type_int, 2); |
| |
| vcType = int16Ty_ ; |
| vcLenJitVal = ConstantInt::get( int16Ty_ , 2 ); |
| DPT0( "VV91002: ", VV_XD, |
| "In case PCIT::MOVE_MATTR5_MATTR5: vcLenJitVal = 2 (16-bit)\n"); |
| } |
| else { |
| //// vcType = jit_type_uint; |
| //// vcLenJitVal = jit_value_create_nint_constant(f, jit_type_int, 4); |
| |
| vcType = int32Ty_ ; |
| vcLenJitVal = ConstantInt::get( int32Ty_ , 4 ); |
| DPT0( "VV91003: ", VV_XD, |
| "In case PCIT::MOVE_MATTR5_MATTR5: vcLenJitVal = 4 (32-bit)\n"); |
| } |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// resJitVal = res->getJitValue(this, f, res->getJitType(), PCBlk); |
| resIRtype = res->getJitType( this ); |
| resJitVal = res->getJitValue(this, Bldr, resIRtype, PCBlk); |
| |
| //// jit_insn_store(f, tRes, resJitVal); |
| //// jit_insn_store(f, tSrc1, src1JitVal); |
| |
| //// jit_value_t srcLen = jit_insn_load_relative(f, src1JitVal, 0, vcType); |
| jit_value_t srcLen = IR_LoadRelativeWithType( Bldr, |
| src1JitVal, 0, vcType ); |
| |
| DPT2( "VV91010: ", VV_XD, "srcLen type = %d, num bits = %d\n", |
| srcLen->getType()->getTypeID(), |
| srcLen->getType()->getIntegerBitWidth() ); |
| DPT2( "VV91011: ", VV_XD, "vcLenJitVal type = %d, num bits = %d\n", |
| vcLenJitVal->getType()->getTypeID(), |
| vcLenJitVal->getType()->getIntegerBitWidth() ); |
| |
| //// srcLen = jit_insn_add(f, srcLen, vcLenJitVal); |
| |
| DPT0( "VV91014: ", VV_VD, |
| "srcLen = Bldr->CreateAdd( srcLen , vcLenJitVal , 'IntAdd' )\n" ); |
| srcLen = Bldr->CreateAdd( srcLen , vcLenJitVal , "IntAdd" ); |
| |
| //// genUnalignedMemcpy(f, tRes, tSrc1, srcLen); |
| DPT0( "VV91016: ", VV_XD, |
| "genUnalignedMemcpy( Bldr, resJitVal, src1JitVal, srcLen )\n"); |
| genUnalignedMemcpy( Bldr, resJitVal, src1JitVal, srcLen ); |
| |
| break; |
| } |
| |
| case PCIT::BRANCH: |
| { |
| //// jit_insn_branch(f, PCBlk->getTargetBlock()->getJitLabel()); |
| |
| p_IR_block_t TgtBlk = *(PCBlk->getTargetBlock()->getJitBlkLbl()) ; |
| |
| DPT1( "VV92010: ", VV_VD, |
| "Bldr->CreateBr( TgtBlk = %p )\n", TgtBlk ); |
| Bldr->CreateBr( TgtBlk ); |
| justHandledUnconditionBranch = TRUE; |
| break; |
| } |
| |
| case PCIT::BRANCH_OR: |
| case PCIT::BRANCH_AND: |
| { |
| PCodeOperand * src1, * res ; |
| jit_value_t src1JitVal, tRes ; |
| p_IR_block_t * IR_Blk_Label = NULL ; |
| |
| src1 = PCInst->getROps()[0]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| jit_value_t takenJitVal = |
| ((opc == PCIT::BRANCH_OR) || (opc == PCIT::BRANCH_OR_CNT)) |
| ? IR_Const_1_ : IR_Const_0_; |
| |
| IR_Blk_Label = PCBlk->getTargetBlock()->getJitBlkLbl(); |
| |
| //// src1JitVal = src1->getJitValue(this, f, jit_type_int, PCBlk); |
| src1JitVal = src1->getJitValue(this, Bldr, int32Ty_, PCBlk); |
| |
| if (res->isVar() || PCBlk->isOperandLiveInSuccs(res)) |
| //// res->storeJitValue(this, f, jit_type_int, src1JitVal, PCBlk, NULL); |
| res->storeJitValue(this, Bldr, int32Ty_, src1JitVal, PCBlk); |
| |
| //// resJitVal = jit_insn_eq(f, src1JitVal, takenJitVal); |
| tRes = jitGenCompare( Bldr, IntCompare_EQ, |
| src1JitVal, takenJitVal , |
| IR_Const_1_ , IR_Const_0_ ); |
| //// jit_insn_branch_if(f, resJitVal, jitLabel); |
| IR_insn_branch_if_not_zero( Bldr, tRes, IR_Blk_Label ); |
| |
| break; |
| } |
| |
| case PCIT::NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S: |
| { |
| PCodeOperand * src1, * src2, * res ; |
| jit_value_t src1JitVal, src2JitVal ; |
| jit_type_t src1IRtype, src2IRtype ; |
| p_IR_block_t * IR_Blk_Label = NULL ; |
| |
| //// jit_label_t src1LabelNull = jit_label_undefined; |
| //// jit_label_t ret1Label = jit_label_undefined; |
| //// jit_label_t endLabel = jit_label_undefined; |
| p_IR_block_t src1LabelNull = BasicBlock::Create( LLContxt, "NNB_SPEC_src1NullBlk" ); |
| p_IR_block_t ret0Label = BasicBlock::Create( LLContxt, "NNB_SPEC_ret0Blk" ); |
| p_IR_block_t endLabel = BasicBlock::Create( LLContxt, "NNB_SPEC_endBlk" ); |
| |
| DPT3( "VV93000: ", VV_XD, |
| "src1LabelNull = %p, ret0Label = %p, endLabel = %p\n", |
| src1LabelNull, ret0Label, endLabel ); |
| |
| //// jitLabel = block->getTargetBlock()->getJitLabel(); |
| IR_Blk_Label = PCBlk->getTargetBlock()->getJitBlkLbl(); |
| |
| //// src1 = inst->getROps()[0]; |
| src1 = PCInst->getROps()[0]; |
| |
| //// src2 = inst->getROps()[1]; |
| src2 = PCInst->getROps()[1]; |
| |
| //// res = inst->getWOps()[0]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| //// jit_insn_branch_if(f, src1JitVal, &src1LabelNull); |
| IR_insn_branch_if_not_zero( Bldr, src1JitVal, &src1LabelNull ); |
| |
| //// jit_insn_branch_if(f, src2JitVal, &ret1Label); <<< RETURNING 1 WAS A BUG |
| IR_insn_branch_if_not_zero( Bldr, src2JitVal, &ret0Label ); |
| |
| // Both are not null - store 0 and take target branch |
| //// res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_0_, PCBlk); |
| |
| //// jit_insn_branch(f, jitLabel); |
| DPT1( "VV93005: ", VV_VD, |
| "Bldr->CreateBr( *IR_Blk_Label = %p )\n", *IR_Blk_Label ); |
| Bldr->CreateBr( *IR_Blk_Label ); |
| |
| // src1 is null - what about src2? |
| //// jit_insn_label(f, &src1LabelNull); |
| |
| // NOTE: We don't need to "complete the current block" since we just generated |
| // an unconditional branch. In fact, LLVM's JIT Compiler aborts if we do |
| // add an additional unconditional branch here. |
| |
| DPT1( "VV93020: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( src1LabelNull = %p )\n", src1LabelNull ); |
| ExpFn->getBasicBlockList().push_back( src1LabelNull ); |
| |
| DPT1( "VV93030: ", VV_VD, |
| "Bldr->SetInsertPoint( src1LabelNull = %p )\n", src1LabelNull ); |
| Bldr->SetInsertPoint( src1LabelNull ); |
| |
| //// jit_insn_branch_if(f, src2JitVal, &ret1Label); <<<< RETURNING 1 WAS A BUG |
| IR_insn_branch_if_zero( Bldr, src2JitVal, &ret0Label ); |
| |
| // src2 is also null, so return 1 |
| //// res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_1_, PCBlk); |
| |
| //// jit_insn_branch(f, &endLabel); |
| |
| DPT1( "VV93040: ", VV_VD, |
| "Bldr->CreateBr( endLabel = %p )\n", endLabel ); |
| Bldr->CreateBr( endLabel ); |
| |
| // Return 1 |
| //// jit_insn_label(f, &ret1Label); |
| |
| // NOTE: We don't need to "complete the current block" since we just generated |
| // an unconditional branch. In fact, LLVM's JIT Compiler aborts if we do |
| // add an additional unconditional branch here. |
| |
| DPT1( "VV93060: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( ret0Label = %p )\n", ret0Label ); |
| ExpFn->getBasicBlockList().push_back( ret0Label ); |
| |
| DPT1( "VV93070: ", VV_VD, |
| "Bldr->SetInsertPoint( ret0Label = %p )\n", ret0Label ); |
| Bldr->SetInsertPoint( ret0Label ); |
| |
| //// res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); <<< THIS WAS A BUG |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_0_, PCBlk); |
| |
| // End label to jump to |
| //// jit_insn_label(f, &endLabel); |
| |
| DPT1( "VV93080: ", VV_VD, |
| "Bldr->CreateBr( endLabel = %p )\n", endLabel ); |
| Bldr->CreateBr( endLabel ); // Must complete the current block |
| |
| DPT1( "VV93090: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( endLabel = %p )\n", endLabel ); |
| ExpFn->getBasicBlockList().push_back( endLabel ); |
| |
| DPT1( "VV93098: ", VV_VD, |
| "Bldr->SetInsertPoint( endLabel = %p )\n", endLabel ); |
| Bldr->SetInsertPoint( endLabel ); |
| |
| break; |
| } |
| |
| case PCIT::NNB_MATTR3_IBIN32S: |
| { |
| PCodeOperand * src1 ; |
| jit_value_t src1JitVal ; |
| jit_type_t src1IRtype ; |
| p_IR_block_t * IR_Blk_Label = NULL ; |
| |
| src1 = PCInst->getROps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// jitLabel = PCBlk->getTargetBlock()->getJitLabel(); |
| IR_Blk_Label = PCBlk->getTargetBlock()->getJitBlkLbl() ; |
| |
| //// jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| IR_insn_branch_if_zero( Bldr, src1JitVal, IR_Blk_Label ); |
| |
| break; |
| } |
| |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| { |
| PCodeOperand * src1, * src2, * res ; |
| jit_type_t src1IRtype, src2IRtype ; |
| jit_value_t src1JitVal, src2JitVal, orResJitVal ; |
| p_IR_block_t * IR_Blk_Label = NULL ; |
| |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| NABoolean forComp = (opc == |
| PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| //// orRes = jit_insn_or(f, src1JitVal, src2JitVal); |
| |
| Int32 src1Width = src1IRtype->getIntegerBitWidth(); |
| Int32 src2Width = src2IRtype->getIntegerBitWidth(); |
| if ( src1Width < src2Width ) |
| { |
| DPT2( "VV94102: ", VV_VD, |
| "src1Width=%d < src2Width=%d\n", src1Width, src2Width); |
| |
| DPT0( "VV94103: ", VV_VD, |
| "src1JitVal = Bldr->CreateZExt( src1JitVal, (IntegerType *)src2IRtype, 'ZExtArg1' )\n" ); |
| src1JitVal = Bldr->CreateZExt( src1JitVal, |
| (IntegerType *)src2IRtype, "ZExtArg1" ) ; |
| } |
| if ( src1Width > src2Width ) |
| { |
| DPT2( "VV94105: ", VV_VD, "src1Width=%d > src2Width=%d\n", |
| src1Width, src2Width); |
| DPT0( "VV94106: ", VV_VD, |
| "src2JitVal = Bldr->CreateZExt( src2JitVal, (IntegerType *)src1IRtype, 'ZExtArg2' )\n" ); |
| src2JitVal = Bldr->CreateZExt( src2JitVal, |
| (IntegerType *)src1IRtype, "ZExtArg2" ) ; |
| } |
| |
| DPT0( "VV94110: ", VV_VD, |
| "orResJitVal = Bldr->CreateOr( src1JitVal, src2JitVal, 'BitwiseOr' )\n" ); |
| orResJitVal = Bldr->CreateOr( src1JitVal, src2JitVal, "BitwiseOr" ); |
| |
| //// jitLabel = block->getTargetBlock()->getJitLabel(); |
| IR_Blk_Label = PCBlk->getTargetBlock()->getJitBlkLbl() ; |
| |
| if (res->isVar() || PCBlk->isOperandLiveInSuccs(res)) { |
| //// res->storeNullJitValueAndBranch(this, f, orRes, jitLabel, |
| //// forComp, block); |
| res->storeNullJitValueAndBranch(this, Bldr, orResJitVal, |
| *IR_Blk_Label, forComp, PCBlk); |
| } |
| else { |
| //// jit_insn_branch_if_not(f, orRes, jitLabel); |
| IR_insn_branch_if_zero( Bldr, orResJitVal, IR_Blk_Label ); |
| } |
| |
| break; |
| } |
| |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| { |
| PCodeOperand * src1, * res ; |
| jit_type_t src1IRtype ; |
| p_IR_block_t * IR_Blk_Label = NULL ; |
| |
| src1 = PCInst->getROps()[0]; |
| res = PCInst->getWOps()[0]; |
| |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| NABoolean forComp = |
| (opc == PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S); |
| |
| // src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| |
| src1IRtype = src1->getJitType( this ); |
| |
| DPT1( "VV95010: ", VV_XD, |
| "In NOT_NULL_BRANCH_MBIN32S... src1's Type ID is %d\n", |
| (int) src1IRtype->getTypeID() ); |
| #if NExprDbgLvl >= VV_XD |
| if ( src1IRtype->isPointerTy() ) |
| DPT0( "VV95011: ", VV_XD, |
| "In NOT_NULL_BRANCH_MBIN32S ... src1IRtype->isPointerTy()" |
| " returned TRUE.\n" ) ; |
| |
| if ( src1IRtype->isPointerTy() ) |
| DPT1( "VV95012: ", VV_XD, |
| "In NOT_NULL_BRANCH_MBIN32S... src1's Contained Type ID is %d\n", |
| (int) src1IRtype->getContainedType(0)->getTypeID() ); |
| #endif |
| |
| jit_value_t src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| DPT1( "VV95014: ", VV_XD, |
| "In NOT_NULL_BRANCH_MBIN32S... Val32's Type ID is %d\n", |
| (int) src1JitVal->getType()->getTypeID() ); |
| |
| //// jitLabel = PCBlk->getTargetBlock()->getJitLabel(); |
| IR_Blk_Label = PCBlk->getTargetBlock()->getJitBlkLbl() ; |
| |
| if (res->isVar() || PCBlk->isOperandLiveInSuccs(res)) { |
| // res->storeNullJitValueAndBranch(this, f, src1JitVal, jitLabel, |
| // forComp, PCBlk); |
| res->storeNullJitValueAndBranch(this, Bldr, src1JitVal, *IR_Blk_Label, |
| forComp, PCBlk); |
| } |
| else { |
| // jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| IR_insn_branch_if_zero( Bldr, src1JitVal, IR_Blk_Label ); |
| } |
| |
| break; |
| } |
| |
| case PCIT::FILL_MEM_BYTES_VARIABLE: |
| case PCIT::FILL_MEM_BYTES: |
| { |
| PCodeOperand *res ; |
| jit_value_t resJitVal ; |
| jit_type_t resIRtype ; |
| |
| #ifdef NO_FILL_MEM_BYTES |
| break; |
| #endif |
| Int32 fillVal, fillLen; |
| |
| res = PCInst->getWOps()[0]; |
| |
| #if NExprDbgLvl >= VV_BD |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| if ( res->getStackIndex() == 2 ) |
| { |
| if ( opc == PCIT::FILL_MEM_BYTES ) |
| { |
| DPT0( "VV95101: ", VV_VD, |
| "found PCIT::FILL_MEM_BYTES: WITH stackIndex_ = 2\n" ); |
| } |
| else |
| { |
| DPT0( "VV95101: ", VV_VD, |
| "found PCIT::FILL_MEM_BYTES_VARIABLE: WITH stackIndex_ = 2\n" ); |
| } |
| } |
| #endif |
| |
| // Also, no need to zero out temporary operands, since we just care |
| // about their values being appropriately nulled out. |
| if (res->isTemp()) |
| break; |
| |
| //// resJitVal = res->getJitValue(this, f, res->getJitType(), PCBlk); |
| resIRtype = res->getJitType( this ); |
| resJitVal = res->getJitValue(this, Bldr, resIRtype, PCBlk); |
| |
| if (opc == PCIT::FILL_MEM_BYTES_VARIABLE) |
| { |
| jit_value_t lenJitVal; |
| |
| Int32 vcLen = res->getVcIndicatorLen(); |
| //// jit_type_t vcType = (vcLen == 2) ? jit_type_ushort : jit_type_uint; |
| jit_type_t vcType = (vcLen == 2) ? int16Ty_ : int32Ty_ ; |
| |
| //// lenJitVal = jit_value_create_nint_constant(f, vcType,inst->code[6]); |
| lenJitVal = ConstantInt::get( vcType , PCInst->code[6] ); |
| |
| // Write out vc length first |
| //// jit_insn_store_relative(f, resJitVal, 0, lenJitVal); |
| |
| DPT0( "VV95110: ", VV_XD, |
| "IR_StoreRelativeWithType( Bldr, lenJitVal, resJitVal, 0, vcType )\n" ); |
| IR_StoreRelativeWithType( Bldr, lenJitVal, resJitVal, 0, vcType ); |
| |
| // Move pointer up |
| //// resJitVal = jit_insn_add_relative(f, resJitVal, vcLen); |
| |
| jit_value_t vcLenVal = ConstantInt::get( int64Ty_ , vcLen ) ; |
| |
| DPT1( "VV95112: ", VV_VD, |
| "resJitVal = Bldr->CreateGEP( resJitVal, %d )\n", vcLen ); |
| resJitVal = Bldr->CreateGEP( resJitVal, vcLenVal ); |
| |
| // Reduce fill length to no longer include vc length indicator |
| fillLen = PCInst->code[6] - vcLen; |
| fillVal = PCInst->code[7]; |
| |
| DPT2( "VV95130: ", VV_XD, |
| "FILL_MEM_BYTES_VARIABLE: Fill Value=0x%x, Fill Len = %d\n", |
| fillVal, fillLen ); |
| } |
| else { |
| fillLen = PCInst->code[3]; |
| fillVal = PCInst->code[4]; |
| |
| DPT2( "VV95140: ", VV_XD, |
| "FILL_MEM_BYTES: Fill Value=0x%x, Fill Len = %d\n", |
| fillVal, fillLen ); |
| } |
| |
| // FIXME: If varchar, we currently set the vc length to the max length |
| // of the varchar, but does that make sense if the value is NULL? |
| // This only gets called when the the varchar is NULL, and so it's |
| // length will always be zero, so why write it out?. |
| |
| //// genUnalignedMemset(f, resJitVal, fillVal, fillLen); |
| genUnalignedMemset( Bldr, resJitVal, fillVal, fillLen ); |
| |
| break; |
| } |
| |
| case PCIT::EQ_MBIN32S_MASCII_MASCII: |
| case PCIT::NE_MBIN32S_MASCII_MASCII: |
| case PCIT::LT_MBIN32S_MASCII_MASCII: |
| case PCIT::GT_MBIN32S_MASCII_MASCII: |
| case PCIT::LE_MBIN32S_MASCII_MASCII: |
| case PCIT::GE_MBIN32S_MASCII_MASCII: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal ; |
| jit_type_t src1IRtype, src2IRtype ; |
| |
| res = PCInst->getWOps()[0]; |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| p_IR_block_t falseLabel = BasicBlock::Create( LLContxt, "XX_M32_MA_MA_falseBlk" ); |
| p_IR_block_t trueLabel = BasicBlock::Create( LLContxt, "XX_M32_MA_MA_trueBlk" ); |
| p_IR_block_t endLabel = BasicBlock::Create( LLContxt, "XX_M32_MA_MA_endBlk" ); |
| |
| DPT0( "VV95150: ", VV_XD, "In Cmp??_MBIN32S_MASCII_MASCII \n" ); |
| |
| Int32 MaxlenInt32 = src1->getLen() ; |
| jit_value_t Maxlen = ConstantInt::get( int32Ty_, MaxlenInt32 ); |
| |
| enum cmpKind KindOfCmp = ByteCompare_EQ ; |
| |
| switch ( opc ) |
| { |
| case PCIT::EQ_MBIN32S_MASCII_MASCII: |
| { break ; } |
| case PCIT::NE_MBIN32S_MASCII_MASCII: |
| { KindOfCmp = ByteCompare_NE ; break ; } |
| case PCIT::LT_MBIN32S_MASCII_MASCII: |
| { KindOfCmp = ByteCompare_LT ; break ; } |
| case PCIT::LE_MBIN32S_MASCII_MASCII: |
| { KindOfCmp = ByteCompare_LE ; break ; } |
| case PCIT::GT_MBIN32S_MASCII_MASCII: |
| { KindOfCmp = ByteCompare_GT ; break ; } |
| case PCIT::GE_MBIN32S_MASCII_MASCII: |
| { KindOfCmp = ByteCompare_GE ; break ; } |
| } |
| // For fixed-length strings, do first few bytes "by hand" |
| // so that we use src1JitVal's jitValue_ field! This is |
| // important so LLVM will believe the src fields have been |
| // accessed. Otherwise, subsequent PCODE instructions that |
| // reference the same operand value may cause LLVM to abort -- thinking |
| // that one path through the PCODE instructions fetched the |
| // first few bytes while another path did not. |
| // NOTE: We put the result of this comparison in IsZero1, but |
| // then we ignore it! What's important is to generate the fetch! |
| // |
| // If src1 has non-null jitValue_ |
| if ( jit_value_t src1CurrJitVal = src1->getCurrJitVal() ) |
| { |
| if ( ( src1CurrJitVal->getType() == int64Ty_ ) && |
| ( MaxlenInt32 >= 8 ) ) |
| { |
| jit_value_t Maxlen64 = ConstantInt::get( int64Ty_, MaxlenInt32 ); |
| |
| DPT0( "VV95154: ", VV_VD, |
| "src1JitVal = src1->getJitValue( this, Bldr, int64Ty_, PCBlk )\n"); |
| src1JitVal = src1->getJitValue( this, Bldr, int64Ty_, PCBlk ); |
| |
| DPT0( "VV95155: ", VV_VD, |
| "jit_value_t IsZero1 = Bldr->CreateICmpEQ( src1JitVal, Maxlen64, 'junkCk' )\n" ); |
| jit_value_t IsZero1 = Bldr->CreateICmpEQ( src1JitVal, Maxlen64, "junkCk" ); |
| } |
| else if ( ( src1CurrJitVal->getType() == int32Ty_ ) && |
| ( MaxlenInt32 >= 4 ) ) |
| { |
| DPT0( "VV95156: ", VV_VD, |
| "src1JitVal = src1->getJitValue( this, Bldr, int32Ty_, PCBlk )\n"); |
| src1JitVal = src1->getJitValue( this, Bldr, int32Ty_, PCBlk ); |
| |
| DPT0( "VV95157: ", VV_VD, |
| "jit_value_t IsZero1 = Bldr->CreateICmpEQ( src1JitVal, Maxlen, 'junkCk' )\n" ); |
| jit_value_t IsZero1 = Bldr->CreateICmpEQ( src1JitVal, Maxlen, "junkCk" ); |
| } |
| else if ( ( src1CurrJitVal->getType() == int16Ty_ ) && |
| ( MaxlenInt32 >= 2 ) ) |
| { |
| jit_value_t Maxlen16 = ConstantInt::get( int16Ty_, MaxlenInt32 ); |
| |
| DPT0( "VV95158: ", VV_VD, |
| "src1JitVal = src1->getJitValue( this, Bldr, int16Ty_, PCBlk )\n"); |
| src1JitVal = src1->getJitValue( this, Bldr, int16Ty_, PCBlk ); |
| |
| DPT0( "VV95159: ", VV_VD, |
| "jit_value_t IsZero1 = Bldr->CreateICmpEQ( src1JitVal, Maxlen16, 'junkCk' )\n" ); |
| jit_value_t IsZero1 = Bldr->CreateICmpEQ( src1JitVal, Maxlen16, "junkCk" ); |
| } |
| } |
| |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| jit_value_t IsZero = genMemCmpLoop( Bldr |
| , KindOfCmp |
| , src1JitVal |
| , src2JitVal |
| , Maxlen |
| ) ; |
| DPT2( "VV95160: ", VV_VD, |
| "Bldr->CreateCondBr( IsZero, trueLabel = %p, falseLabel = %p )\n", trueLabel, falseLabel ); |
| Bldr->CreateCondBr( IsZero, trueLabel, falseLabel ); |
| |
| DPT1( "VV95162: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( trueLabel = %p )\n", trueLabel ); |
| ExpFn->getBasicBlockList().push_back( trueLabel ); |
| |
| DPT1( "VV95164: ", VV_VD, |
| "Bldr->SetInsertPoint( trueLabel = %p )\n", trueLabel ); |
| Bldr->SetInsertPoint( trueLabel ); |
| |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_1_, PCBlk); |
| |
| DPT1( "VV95166: ", VV_VD, |
| "Bldr->CreateBr( endLabel = %p )\n", endLabel ); |
| Bldr->CreateBr( endLabel ); |
| |
| DPT1( "VV95168: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( falseLabel = %p )\n", falseLabel ); |
| ExpFn->getBasicBlockList().push_back( falseLabel ); |
| |
| DPT1( "VV95170: ", VV_VD, |
| "Bldr->SetInsertPoint( falseLabel = %p )\n", falseLabel ); |
| Bldr->SetInsertPoint( falseLabel ); |
| |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_0_, PCBlk); |
| |
| DPT1( "VV95172: ", VV_VD, |
| "Bldr->CreateBr( endLabel = %p )\n", endLabel ); |
| Bldr->CreateBr( endLabel ); // Must complete the current block |
| |
| DPT1( "VV95174: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( endLabel = %p )\n", endLabel ); |
| ExpFn->getBasicBlockList().push_back( endLabel ); |
| |
| DPT1( "VV95179: ", VV_VD, |
| "Bldr->SetInsertPoint( endLabel = %p )\n", endLabel ); |
| Bldr->SetInsertPoint( endLabel ); |
| |
| break; |
| } |
| |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S: |
| case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| res = PCInst->getWOps()[0]; |
| |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| #if NExprDbgLvl >= VV_VD |
| if (src1 == src2) |
| DPT0( "VV96002: ", VV_XD, |
| "In EQ_MBIN32S_MBINxxS_MBINxxS: src1 == src2 !!!\n"); |
| #endif |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| src1IRtype = src1->getJitType( this ); |
| |
| DPT1( "VV96004: ", VV_XD, |
| "In EQ_MBIN32S_MBINxxS_MBINxxS: src1IRtype Width = %d\n", |
| src1IRtype->getIntegerBitWidth() ); |
| |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), PCBlk); |
| src2IRtype = src2->getJitType( this ); |
| |
| DPT1( "VV96006: ", VV_XD, |
| "In EQ_MBIN32S_MBINxxS_MBINxxS: src2IRtype Width = %d\n", |
| src2IRtype->getIntegerBitWidth() ); |
| |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| //// resJitVal = jit_insn_eq(f, src1JitVal, src2JitVal); |
| if ( opc == PCIT::EQ_MBIN32S_MBIN16S_MBIN32S ) |
| { |
| DPT0( "VV96010: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt(src1JitVal, (IntegerType *)src2IRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)src2IRtype, "SExt" ) ; |
| } |
| if ( opc == PCIT::EQ_MBIN32S_MBIN16U_MBIN32U ) |
| { |
| DPT0( "VV96020: ", VV_VD, |
| "src1JitVal = Bldr->CreateZExt( src1JitVal, (IntegerType *)src2IRtype, 'ZExt' )\n" ); |
| src1JitVal = Bldr->CreateZExt( src1JitVal, |
| (IntegerType *)src2IRtype, "ZExt" ) ; |
| } |
| resJitVal = jitGenCompare( Bldr, IntCompare_EQ, |
| src1JitVal, src2JitVal, |
| IR_Const_1_ , IR_Const_0_ ); |
| |
| DPT0( "VV96024: ", VV_XD, |
| "In EQ_MBIN32S_MBINxxS_MBINxxS: Returned from jitGenCompare\n"); |
| |
| //// inst->getWOps()[0]->setJitValue(this, f, resJitVal, PCBlk); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| DPT0( "VV96026: ", VV_XD, |
| "In EQ_MBIN32S_MBINxxS_MBINxxS: Returned from setJitValue\n"); |
| break; |
| } |
| |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN32U_MBIN32U: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| //// resJitVal = jit_insn_lt(f, src1JitVal, src2JitVal); |
| if ( opc == PCIT::LT_MBIN32S_MBIN16S_MBIN32S ) |
| { |
| DPT0( "VV96510: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt( src1JitVal, (IntegerType *)src2IRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)src2IRtype, "SExt" ) ; |
| } |
| if ( opc == PCIT::LT_MBIN32S_MBIN16U_MBIN32U ) |
| { |
| DPT0( "VV96520: ", VV_VD, |
| "src1JitVal = Bldr->CreateZExt( src1JitVal, (IntegerType *)src2IRtype, 'ZExt' )\n" ); |
| src1JitVal = Bldr->CreateZExt( src1JitVal, |
| (IntegerType *)src2IRtype, "ZExt" ) ; |
| } |
| |
| enum cmpKind KindOfCmp = IntCompare_SLT ; |
| switch (opc) |
| { |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN32U_MBIN32U: |
| KindOfCmp = IntCompare_ULT ; |
| break; |
| default: |
| break; |
| } |
| resJitVal = jitGenCompare( Bldr, KindOfCmp, |
| src1JitVal, src2JitVal, |
| IR_Const_1_ , IR_Const_0_ ); |
| |
| //// inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| break; |
| } |
| |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN64S_MBIN64S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| //// resJitVal = jit_insn_le(f, src1JitVal, src2JitVal); |
| |
| if ( opc == PCIT::LE_MBIN32S_MBIN16S_MBIN32S ) |
| { |
| DPT0( "VV96610: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt( src1JitVal, (IntegerType *)src2IRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)src2IRtype, "SExt" ) ; |
| } |
| if ( opc == PCIT::LE_MBIN32S_MBIN16U_MBIN32U ) |
| { |
| DPT0( "VV96620: ", VV_VD, |
| "src1JitVal = Bldr->CreateZExt( src1JitVal, (IntegerType *)src2IRtype, 'ZExt' )\n" ); |
| src1JitVal = Bldr->CreateZExt( src1JitVal, |
| (IntegerType *)src2IRtype, "ZExt" ) ; |
| } |
| |
| enum cmpKind KindOfCmp = IntCompare_SLE ; |
| switch (opc) |
| { |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN32U_MBIN32U: |
| KindOfCmp = IntCompare_ULE ; |
| break; |
| default: |
| break; |
| } |
| resJitVal = jitGenCompare( Bldr, KindOfCmp, |
| src1JitVal, src2JitVal, |
| IR_Const_1_ , IR_Const_0_ ); |
| |
| //// inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| break; |
| } |
| |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN64S_MBIN64S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| //// resJitVal = jit_insn_gt(f, src1JitVal, src2JitVal); |
| if ( opc == PCIT::GT_MBIN32S_MBIN16S_MBIN32S ) |
| { |
| DPT0( "VV96710: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt( src1JitVal, (IntegerType *)src2IRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)src2IRtype, "SExt" ) ; |
| } |
| if ( opc == PCIT::GT_MBIN32S_MBIN16U_MBIN32U ) |
| { |
| DPT0( "VV96720: ", VV_VD, |
| "src1JitVal = Bldr->CreateZExt( src1JitVal, (IntegerType *)src2IRtype, 'ZExt' )\n" ); |
| src1JitVal = Bldr->CreateZExt( src1JitVal, |
| (IntegerType *)src2IRtype, "ZExt" ) ; |
| } |
| |
| enum cmpKind KindOfCmp = IntCompare_SGT ; |
| switch (opc) |
| { |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN32U_MBIN32U: |
| KindOfCmp = IntCompare_UGT ; |
| break; |
| default: |
| break; |
| } |
| resJitVal = jitGenCompare( Bldr, KindOfCmp, |
| src1JitVal, src2JitVal, |
| IR_Const_1_ , IR_Const_0_ ); |
| |
| //// inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| break; |
| } |
| |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN64S_MBIN64S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| //// resJitVal = jit_insn_ge(f, src1JitVal, src2JitVal); |
| if ( opc == PCIT::GE_MBIN32S_MBIN16S_MBIN32S ) |
| { |
| DPT0( "VV96810: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt( src1JitVal, (IntegerType *)src2IRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)src2IRtype, "SExt" ) ; |
| } |
| if ( opc == PCIT::GE_MBIN32S_MBIN16U_MBIN32U ) |
| { |
| DPT0( "VV96820: ", VV_VD, |
| "src1JitVal = Bldr->CreateZExt( src1JitVal, (IntegerType *)src2IRtype, 'ZExt' )\n" ); |
| src1JitVal = Bldr->CreateZExt( src1JitVal, |
| (IntegerType *)src2IRtype, "ZExt" ) ; |
| } |
| |
| enum cmpKind KindOfCmp = IntCompare_SGE ; |
| switch (opc) |
| { |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN32U_MBIN32U: |
| KindOfCmp = IntCompare_UGE ; |
| break; |
| default: |
| break; |
| } |
| resJitVal = jitGenCompare( Bldr, KindOfCmp, |
| src1JitVal, src2JitVal, |
| IR_Const_1_ , IR_Const_0_ ); |
| |
| //// inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| break; |
| } |
| |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN32S_MBIN32S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S: |
| { |
| PCodeOperand *src1, *src2, *src3, *res ; |
| jit_value_t src1JitVal, src2JitVal, src3JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype, src3IRtype, resIRtype ; |
| |
| //// jit_label_t sumLabel = jit_label_undefined; |
| //// jit_label_t doneLabel = jit_label_undefined; |
| |
| p_IR_block_t sumLabel = BasicBlock::Create( LLContxt, "SUM_MATTR3sumBlk" ); |
| p_IR_block_t doneLabel = BasicBlock::Create( LLContxt, "SUM_MATTR3doneBlk" ); |
| |
| DPT2( "VV96902: ", VV_XD, "sumLabel = %p, doneLabel = %p\n", |
| sumLabel, doneLabel ); |
| |
| |
| // Must do getJitValue(...) calls *before* we do calls to |
| // IR_insn_branch_if_[not]_zero(). If we call getJitValue(...) |
| // after such a conditional branch and if a subsequent |
| // PCODE instruction in the same PC block references the same |
| // PCodeOperand, the jitValue_ member variable will be filled in |
| // and we would fail to tell LLVM to generate a "load" instruction |
| // for the path when we take the conditional branch. |
| // |
| // Note: LLVM's JIT Compiler is smart enough to rearrange the code |
| // as appropriate to avoid actually doing the 'load' instructions |
| // when they are not needed. |
| // |
| res = PCInst->getWOps()[(PCInst->getWOps()).entries()-1]; |
| PRINT_DETAILS_OF_WROp( (PCInst->getWOps()).entries()-1, res ); |
| |
| src3 = PCInst->getROps()[(PCInst->getROps()).entries()-1]; |
| PRINT_DETAILS_OF_RDOp( (PCInst->getROps()).entries()-1, src3 ); |
| |
| //// resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| resIRtype = res->getJitType( this ); |
| resJitVal = res->getJitValue(this, Bldr, resIRtype, PCBlk); |
| |
| //// src3JitVal = src3->getJitValue(this, f, src3->getJitType(), block); |
| src3IRtype = src3->getJitType( this ); |
| src3JitVal = src3->getJitValue(this, Bldr, src3IRtype, PCBlk); |
| |
| // NOW, First check if src is null - if so, we just branch out and return. |
| src2 = PCInst->getROps()[1]; |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| if (!src2->isConst()) { |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| // For LLVM, do nothing here as we already did this above. |
| |
| DPT0( "VV96904: ", VV_XD, |
| "GOT INTO if (!src2->isConst()) section.\n"); |
| |
| //// jit_insn_branch_if(f, src2JitVal, &doneLabel); |
| IR_insn_branch_if_not_zero( Bldr, src2JitVal, &doneLabel ); |
| } |
| else { |
| // Skip check, since constant will be 0 (assert here to verify). |
| DPT0( "VV96906: ", VV_XD, |
| "GOT INTO if (!src2->isConst()) section.\n"); |
| } |
| |
| |
| // Now check if target is null. If so, we just move the src into tgt. |
| src1 = PCInst->getROps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| // |
| // NOTE: MUST sign extend (or truncate) src3JitVal to the size |
| // of the number of bits wide that resIRtype specifies. |
| // FURTHERMORE, this MUST be done *BEFORE* we test src3JitVal |
| // for zero and do any branching. If we don't, the LLVM JIT |
| // Compiler will abort with an assert indicating |
| // "Can't find reaching def for virtreg". |
| // Hitting that assert indicates that there are two or more paths |
| // to an LLVM BasicBlock where not all of the paths have the |
| // defined a temp variable (or not defined it in the same way). |
| // In this particular case, src3JitVal could have two different |
| // definitions (different bit widths) when we got to "sumLabel". |
| // |
| Int32 src1Width = src1IRtype->getIntegerBitWidth(); |
| Int32 src3Width = src3IRtype->getIntegerBitWidth(); |
| Int32 resWidth = resIRtype->getIntegerBitWidth(); |
| |
| DPT3( "VV96910: ", VV_XD, "resWidth=%d, src1Width=%d, src3Width=%d\n", |
| resWidth, src1Width, src3Width ); |
| if ( src3Width != resWidth ) |
| { |
| DPT0( "VV96915: ", VV_VD, |
| "src3JitVal = Bldr->CreateSExtOrTrunc( src3JitVal, (IntegerType *)resIRtype, 'SExtOrTr' )\n" ); |
| src3JitVal = Bldr->CreateSExtOrTrunc( src3JitVal, |
| (IntegerType *)resIRtype, "SExtOrTr" ) ; |
| } |
| |
| // If src1 indicates tgt is not null, take branch to sumLabel |
| //// jit_insn_branch_if_not(f, src1JitVal, &sumLabel); |
| IR_insn_branch_if_zero( Bldr, src1JitVal, &sumLabel ); |
| |
| |
| // At this point, we know the tgt is null. So, we set tgt's value to 0 |
| // and ADD src3's value by simply setting the value of target to src3's |
| // value and clearing the null indicator for the tgt. |
| // |
| //// res->storeJitValue(this, f, res->getJitType(), src3JitVal, block); |
| res->storeJitValue(this, Bldr, resIRtype, src3JitVal, PCBlk); |
| |
| // Clear null indicator for target (by setting src1's value to 0) & branch to doneLabel |
| //// src1->storeNullJitValueAndBranch(this, f, zeroJitVal_, &doneLabel, |
| //// FALSE, block); |
| |
| jit_value_t Const_0 = IR_Const_16bit_0_ ; |
| if ( src1Width == 32 ) Const_0 = IR_Const_0_ ; |
| |
| src1->storeNullJitValueAndBranch(this, Bldr, Const_0, |
| doneLabel, FALSE, PCBlk); |
| |
| // NOTE: At runtime, the only way to get to sumLabel is by taking |
| // the branch (above.) |
| |
| // Perform the sum here |
| //// jit_insn_label(f, &sumLabel); |
| |
| DPT1( "VV96920: ", VV_VD, |
| "Bldr->CreateBr( sumLabel = %p )\n", sumLabel ); |
| Bldr->CreateBr( sumLabel ); // Must complete the current block |
| |
| DPT1( "VV96922: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( sumLabel = %p )\n", sumLabel ); |
| ExpFn->getBasicBlockList().push_back( sumLabel ); |
| |
| DPT1( "VV96924: ", VV_VD, |
| "Bldr->SetInsertPoint( sumLabel = %p )\n", sumLabel ); |
| Bldr->SetInsertPoint( sumLabel ); |
| |
| //// resJitVal = jit_insn_add(f, resJitVal, src3JitVal); |
| |
| DPT0( "VV96927: ", VV_VD, |
| "resJitVal = Bldr->CreateAdd( resJitVal, src3JitVal, 'IntAdd' )\n" ); |
| resJitVal = Bldr->CreateAdd( resJitVal, src3JitVal, "IntAdd" ); |
| |
| //// res->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| //// jit_insn_label(f, &doneLabel); |
| |
| DPT1( "VV96930: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); // Must complete the current block |
| |
| DPT1( "VV96932: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( doneLabel = %p )\n", doneLabel ); |
| ExpFn->getBasicBlockList().push_back( doneLabel ); |
| |
| DPT1( "VV96934: ", VV_VD, |
| "Bldr->SetInsertPoint( doneLabel = %p )\n", doneLabel ); |
| Bldr->SetInsertPoint( doneLabel ); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if ( resWidth > src3Width ) |
| src3->clearJitValues(this); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN16U_MBIN8: |
| case PCIT::MOVE_MBIN32U_MBIN16U: |
| case PCIT::MOVE_MBIN32S_MBIN16U: |
| case PCIT::MOVE_MBIN64S_MBIN16U: |
| case PCIT::MOVE_MBIN64S_MBIN32U: |
| { |
| PCodeOperand *src1, *res ; |
| jit_value_t src1JitVal ; |
| jit_type_t src1IRtype, resIRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| src1IRtype = src1->getJitType( this ); |
| |
| // src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| // src1JitVal = jit_insn_convert(f, src1JitVal, res->getJitType(), 0); |
| |
| resIRtype = res->getJitType( this ); |
| |
| // NOTE: We always Zero Extend because the src1 operand is UNSIGNED |
| |
| DPT0( "VV97010: ", VV_VD, |
| "src1JitVal = Bldr->CreateZExt( src1JitVal, (IntegerType *)resIRtype, 'ZExt' )\n" ); |
| src1JitVal = Bldr->CreateZExt( src1JitVal, |
| (IntegerType *)resIRtype, "ZExt" ) ; |
| |
| // res->storeJitValue(this, f, res->getJitType(), src1JitVal, PCBlk); |
| res->storeJitValue(this, Bldr, resIRtype, src1JitVal, PCBlk); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if ( (opc == PCIT::MOVE_MBIN64S_MBIN16U) || |
| (opc == PCIT::MOVE_MBIN64S_MBIN32U) ) |
| src1->clearJitValues(this); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN32U_MBIN16S: |
| case PCIT::MOVE_MBIN32S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN32S: |
| { |
| PCodeOperand *src1, *res ; |
| jit_value_t src1JitVal, resJitVal ; |
| jit_type_t src1IRtype, resIRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| src1IRtype = src1->getJitType( this ); |
| |
| DPT1( "VV98010: ", VV_XD, "typeID = %d\n", |
| (int) src1IRtype->getTypeID() ); |
| |
| #if NExprDbgLvl >= VV_XD |
| if ( src1IRtype->getTypeID() == Type::IntegerTyID ) |
| DPT1( "VV98011: ", VV_XD, "Integer Type - Number of bits = %d\n", |
| src1IRtype->getIntegerBitWidth() ); |
| #endif |
| |
| // src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| // src1JitVal = jit_insn_convert(f, src1JitVal, res->getJitType(), 0); |
| |
| resIRtype = res->getJitType( this ); |
| |
| DPT1( "VV98012: ", VV_XD, "typeID = %d\n", |
| (int) resIRtype->getTypeID() ); |
| |
| #if NExprDbgLvl >= VV_XD |
| if ( resIRtype->getTypeID() == Type::IntegerTyID ) |
| DPT1( "VV98013: ", VV_XD,"res Integer Type - Number of bits = %d\n", |
| resIRtype->getIntegerBitWidth() ); |
| #endif |
| |
| llvm::IntegerType * IntTyp = IntegerType::get( LLContxt, |
| resIRtype->getIntegerBitWidth() ); |
| |
| DPT1( "VV98014: ", VV_XD, "IntTyp - Number of bits = %d\n", |
| IntTyp->getIntegerBitWidth() ); |
| |
| // NOTE: We always Sign Extend because the src1 operand is SIGNED |
| |
| DPT0( "VV98016: ", VV_VD, |
| "resJitVal = Bldr->CreateSExtOrTrunc( src1JitVal, IntTyp, 'SExt' )\n" ); |
| resJitVal = Bldr->CreateSExtOrTrunc( src1JitVal, IntTyp, "SExt" ) ; |
| |
| // res->storeJitValue(this, f, res->getJitType(), resJitVal, PCBlk); |
| res->storeJitValue(this, Bldr, resIRtype, resJitVal, PCBlk); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if ( (opc == PCIT::MOVE_MBIN64S_MBIN16S) || |
| (opc == PCIT::MOVE_MBIN64S_MBIN32S) ) |
| src1->clearJitValues(this); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN16U_IBIN16U: |
| case PCIT::MOVE_MBIN32S_IBIN32S: |
| { |
| PCodeOperand *res ; |
| jit_value_t src1JitVal ; |
| jit_type_t resIRtype ; |
| |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| // type = (opc == PCIT::MOVE_MBIN32S_IBIN32S) ? jit_type_int : jit_type_ushort; |
| resIRtype = (opc == PCIT::MOVE_MBIN32S_IBIN32S) ? int32Ty_ : int16Ty_; |
| |
| Int32 val = PCInst->code[3]; |
| |
| // src1JitVal = jit_value_create_nint_constant(f, type, val); |
| // res->storeJitValue(this, f, type, src1JitVal, PCBlk); |
| |
| src1JitVal = ConstantInt::get( resIRtype, val ); |
| |
| DPT1( "VV99010: ", VV_VD, |
| "res->storeJitValue(this, Bldr, resIRtype, src1JitVal=Const of %d, PCBlk)\n", val); |
| res->storeJitValue(this, Bldr, resIRtype, src1JitVal, PCBlk); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN16U_MBIN16U: |
| case PCIT::MOVE_MBIN8_MBIN8: |
| case PCIT::MOVE_MBIN8_MBIN8_IBIN32S: |
| case PCIT::MOVE_MBIN32U_MBIN32U: |
| case PCIT::MOVE_MBIN64S_MBIN64S: |
| { |
| PCodeOperand *src1, *res ; |
| jit_value_t src1JitVal, resJitVal ; |
| jit_type_t src1IRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| src1IRtype = src1->getJitType( this ); |
| |
| DPT1( "VV9A011: ", VV_XD, "For src1, src1IRtype->getTypeID() == %d\n", |
| src1IRtype->getTypeID() ); |
| |
| #if NExprDbgLvl >= VV_XD |
| if ( src1IRtype->getTypeID()==Type::IntegerTyID ) |
| DPT1( "VV9A015: ", VV_XD, "BitWidth=%d\n", |
| src1IRtype->getIntegerBitWidth()); |
| #endif |
| if ( src1IRtype == int8PtrTy_ ) |
| assert (opc == PCIT::MOVE_MBIN8_MBIN8_IBIN32S); |
| |
| #if NExprDbgLvl >= VV_BD |
| if (opc == PCIT::MOVE_MBIN8_MBIN8_IBIN32S) |
| { |
| DPT1( "VV9A020: ", VV_XD, "src1->stackIndex_ = %d\n", |
| src1->getStackIndex() ); |
| DPT1( "VV9A021: ", VV_XD, "res->stackIndex_ = %d\n", |
| res->getStackIndex() ); |
| if ( src1IRtype->isPointerTy() ) |
| DPT1( "VV9A022: ", VV_XD, |
| "src1IRtype->getContainedType(0)->getTypeID() = %d\n", |
| src1IRtype->getContainedType(0)->getTypeID() ); |
| } |
| #endif |
| |
| DPT0( "VV9A026: ", VV_VD, |
| "src1JitVal = src1->getJitValue( this, Bldr, src1IRtype, PCBlk )\n"); |
| |
| src1JitVal = src1->getJitValue( this, Bldr, src1IRtype, PCBlk ); |
| |
| DPT1( "VV9A027: ", VV_XD,"src1JitVal->getType()->getTypeID() == %d\n", |
| src1JitVal->getType()->getTypeID() ); |
| #if NExprDbgLvl >= VV_BD |
| if ( src1JitVal->getType()->isPointerTy() ) |
| DPT1( "VV9A027A: ", VV_XD, "src1JitVal IS PointerType -> %d\n", |
| src1JitVal->getType()->getContainedType(0)->getTypeID() ); |
| |
| if ( src1JitVal->getType()->getTypeID() == Type::IntegerTyID ) |
| DPT1( "VV9A027B: ", VV_XD, "src1JitVal IS Int Type. BitWidth = %d\n", |
| src1JitVal->getType()->getIntegerBitWidth() ); |
| #endif |
| |
| DPT2( "VV9A027D: ", VV_XD, |
| "src1IRtype is at %p, src1JitVal->getType() is at %p\n", |
| src1IRtype, src1JitVal->getType() ); |
| |
| DPT1( "VV9A028: ", VV_XD, "src1JitVal is at %p\n", src1JitVal ); |
| |
| DPT0( "VV9A030: ", VV_VD, |
| "res->storeJitValue(this, Bldr, src1IRtype, src1JitVal, PCBlk)\n" ); |
| |
| res->storeJitValue(this, Bldr, src1IRtype, src1JitVal, PCBlk); |
| |
| break; |
| } |
| |
| case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S: |
| { |
| PCodeOperand *src1, *res ; |
| jit_value_t src1JitVal, resJitVal ; |
| jit_type_t src1IRtype ; |
| |
| src1 = PCInst->getROps()[0]; |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| NABoolean testForNull = (PCInst->code[9] != 0); |
| |
| // Generate more efficient code if next instruction is logical branch |
| if (PCInst->next && PCInst->next->isAnyLogicalBranch()) |
| { |
| NABoolean srcLive, tgtLive; |
| |
| PCodeInst* branch = PCInst->next; |
| |
| PCodeOperand* bSrc = branch->getROps()[0]; |
| PCodeOperand* bTgt = branch->getWOps()[0]; |
| |
| // Is source or target live after branch? |
| srcLive = bSrc->isVar() || PCBlk->isOperandLiveInSuccs(bSrc); |
| tgtLive = bTgt->isVar() || PCBlk->isOperandLiveInSuccs(bTgt); |
| |
| // Only generate efficient path if the null-test is associated with |
| // the branch, and that both the src and tgt of the branch are not |
| // live (which would otherwise require one or more stores). |
| if ((bSrc->getBvIndex()==res->getBvIndex()) && !srcLive && !tgtLive) |
| { |
| //// jitLabel = PCBlk->getTargetBlock()->getJitLabel(); |
| p_IR_block_t * IR_Blk_Label = |
| PCBlk->getTargetBlock()->getJitBlkLbl(); |
| |
| // Branch to destination according to the test performed. |
| switch (branch->getOpcode()) { |
| case PCIT::BRANCH_OR: |
| case PCIT::BRANCH_OR_CNT: |
| if (testForNull) |
| //// jit_insn_branch_if(f, src1JitVal, jitLabel); |
| IR_insn_branch_if_not_zero( Bldr, src1JitVal, IR_Blk_Label ); |
| else |
| //// jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| IR_insn_branch_if_zero(Bldr, src1JitVal, IR_Blk_Label); |
| break; |
| |
| case PCIT::BRANCH_AND: |
| case PCIT::BRANCH_AND_CNT: |
| if (testForNull) |
| //// jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| IR_insn_branch_if_zero(Bldr, src1JitVal, IR_Blk_Label); |
| else |
| //// jit_insn_branch_if(f, src1JitVal, jitLabel); |
| IR_insn_branch_if_not_zero( Bldr, src1JitVal, IR_Blk_Label ); |
| break; |
| } |
| |
| // Skip the next instruction (branch) since it was handled here. |
| skipInst = 1; |
| break; |
| } |
| } |
| else if (PCInst->next && PCInst->next->getOpcode() == PCIT::MOVE_MBIN32S) |
| { |
| PCodeInst* move = PCInst->next; |
| if (res->getBvIndex() == move->getROps()[0]->getBvIndex()) |
| { |
| //// jit_label_t l1 = jit_label_undefined; |
| |
| // A RETURN is guaranteed to following a MOVE_MBIN32S |
| assert (move->next && (move->next->getOpcode() == PCIT::RETURN)); |
| |
| enum cmpKind KindOfCmp = IntCompare_EQ ; |
| if ( testForNull ) KindOfCmp = IntCompare_NE ; |
| |
| jit_value_t Zero = ConstantInt::get( src1JitVal->getType(), 0 ); |
| resJitVal = jitGenCompare( Bldr, KindOfCmp, |
| src1JitVal, Zero , |
| IR_Const_TRUE_, IR_Const_FALSE_ ); |
| |
| DPT0( "VV9A360: ", VV_VD, "returned from jitGenCompare()\n"); |
| |
| DPT0( "VV9A361: ", VV_VD, |
| "Bldr->CreateRet( resJitVal )\n" ); |
| Bldr->CreateRet( resJitVal ); |
| |
| justGeneratedRET = TRUE; |
| |
| //// if (testForNull) |
| //// jit_insn_branch_if(f, src1JitVal, &l1); |
| //// else |
| //// jit_insn_branch_if_not(f, src1JitVal, &l1); |
| |
| //// jit_insn_return(f, fJitVal_); |
| |
| //// jit_insn_label(f, &l1); |
| //// jit_insn_return(f, tJitVal_); |
| |
| // Skip the next 2 instructions since it was handled here. |
| skipInst = 2; |
| break; |
| } |
| } |
| |
| // Fall-through (default) case to implement NULL_TEST |
| |
| //// if (testForNull) |
| //// resJitVal = jit_insn_ne(f, src1JitVal, zeroJitVal_); |
| //// else |
| //// resJitVal = jit_insn_eq(f, src1JitVal, zeroJitVal_); |
| |
| enum cmpKind KindOfCmp = IntCompare_EQ ; |
| if ( testForNull ) KindOfCmp = IntCompare_NE ; |
| |
| jit_value_t Zero = ConstantInt::get( src1JitVal->getType(), 0 ); |
| resJitVal = jitGenCompare( Bldr , KindOfCmp , |
| src1JitVal , Zero , |
| IR_Const_1_ , IR_Const_0_ ); |
| |
| DPT0( "VV9A380: ", VV_VD, "returned from jitGenCompare()\n"); |
| |
| //// inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| res->setJitValue( this, Bldr, resJitVal, PCBlk); |
| |
| break; |
| } |
| |
| case PCIT::MINMAX_MBIN8_MBIN8_MBIN32S_IBIN32S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal ; |
| jit_type_t src1IRtype ; |
| |
| //// jit_type_t type; |
| //// jit_label_t doneLabel = jit_label_undefined; |
| |
| p_IR_block_t doneLabel = BasicBlock::Create( LLContxt, "MinMaxDoneBlk" ); |
| |
| DPT1( "VV9A501: ", VV_XD, "doneLabel = %p\n", doneLabel ); |
| |
| src1 = PCInst->getROps()[0]; // Source pointer |
| src2 = PCInst->getROps()[1]; // Result of comparison |
| res = PCInst->getWOps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| |
| //// src2JitVal = src2->getJitValue(this, f, jit_type_int, block); |
| src2JitVal = src2->getJitValue(this, Bldr, int32Ty_, PCBlk); |
| |
| // Get type associated with length, since generic MBINS is used to |
| // represent source/tgt. If not, getJitType() is called, and it will |
| // assume we're dealing with a void ptr by default. |
| |
| switch(src1->getLen()) { |
| case 1: |
| //// type = jit_type_ubyte; |
| src1IRtype = int8Ty_; |
| break; |
| case 2: |
| //// type = jit_type_ushort; |
| src1IRtype = int16Ty_; |
| break; |
| case 4: |
| //// type = jit_type_uint; |
| src1IRtype = int32Ty_; |
| break; |
| case 8: |
| //// type = jit_type_long; |
| src1IRtype = int64Ty_; |
| break; |
| default: |
| { |
| //// type = jit_type_void_ptr; |
| src1IRtype = int1PtrTy_; |
| break; |
| } |
| } |
| |
| //// src1JitVal = src1->getJitValue(this, f, type, block); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// jit_insn_branch_if_not(f, src2JitVal, &doneLabel); |
| IR_insn_branch_if_zero( Bldr, src2JitVal, &doneLabel ); |
| |
| |
| //// res->setJitValue(this, f, src1JitVal, block); |
| res->setJitValue( this, Bldr, src1JitVal, PCBlk ); |
| |
| //// jit_insn_label(f, &doneLabel); |
| |
| DPT1( "VV9A520: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); // Must complete the current block |
| |
| DPT1( "VV9A522: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( doneLabel = %p )\n", doneLabel ); |
| ExpFn->getBasicBlockList().push_back( doneLabel ); |
| |
| DPT1( "VV9A524: ", VV_VD, |
| "Bldr->SetInsertPoint( doneLabel = %p )\n", doneLabel ); |
| Bldr->SetInsertPoint( doneLabel ); |
| |
| break; |
| } |
| |
| case PCIT::OPDATA_MPTR32_IBIN32S: |
| case PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S: |
| case PCIT::OPDATA_MBIN16U_IBIN32S: |
| case PCIT::OPDATA_MATTR5_IBIN32S: |
| { |
| OPLIST opList = (PCInst->getWOps().entries() ? |
| PCInst->getWOps() : PCInst->getROps() ); |
| |
| DPT1( "VV9B001: ", VV_XD, "In OPDATA_*, using %s operands!\n", |
| PCInst->getWOps().entries() ? "WRITE": "READ" ); |
| |
| #if NExprDbgLvl >= VV_BD |
| for (Int32 iii = 0; iii < opList.entries(); iii++ ) |
| { |
| DPT2( "VV9B002: ", VV_XD, |
| "In OPDATA_*, opList[%d] = %p\n", iii, opList[iii] ); |
| |
| DPT1( "VV9B002a: ", VV_XD, |
| "Details of opList[%d] *BEFORE setupClauseOperand* are:\n", |
| iii ); |
| PCodeOperand *PCOp = opList[iii]; |
| if (!PCOp) continue; |
| |
| DPT6( "VV9B002b: ", VV_XD, |
| "stackIndex_ = %d, offset_ = %d, len_=%d, operandType_=%d, nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| } |
| #endif |
| |
| Int32 index = |
| (opc == PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S) ? |
| PCInst->code[4] : ( (opc == PCIT::OPDATA_MATTR5_IBIN32S) ? |
| PCInst->code[6] : PCInst->code[3] ); |
| |
| DPT1( "VV9B003: ", VV_XD, "OPDATA_* - index = %d\n", index ); |
| |
| #if NExprDbgLvl >= VV_BD |
| for ( Int32 jjj = 0; (jjj <= index) && (jjj < opList.entries()); jjj++) |
| { |
| DPT2( "VV9B004: ", VV_XD, "OPDATA_* BEFORE opData[%d] = %p\n", jjj, opData[jjj]); |
| if ( opData[jjj] ) |
| { |
| DPT1( "VV9B005: ", VV_XD, |
| "Details of opData[%d] *BEFORE setupClauseOperand* are:\n", |
| jjj ); |
| |
| PCodeOperand *PCOp = opData[jjj]; |
| |
| DPT6( "VV9B006: ", VV_XD, |
| "stackIndex_ = %d, offset_ = %d, len_=%d, operandType_=%d, nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| } |
| } |
| #endif |
| // Add the "correct" operand for this opdata instruction, replacing |
| // the old one in the operand list used during pcode opts. |
| setupClauseOperand(this, opList, opData, index, PCInst->clause_); |
| |
| // |
| // We must ensure Write Operands have space allocated for them |
| // *before* we generated any conditional branches. |
| // NOTE: It is possible that a case will be found in the future when |
| // we need to have allocJitValue() called *before* the main loop. |
| if ( PCInst->getWOps().entries() ) |
| { |
| for ( Int32 nnn = 0; (nnn <= index) && (nnn < opList.entries()); nnn++) |
| { |
| PCodeOperand * Oper = opData[nnn] ; |
| if ( ! Oper ) continue; |
| |
| DPT0( "VV9B006a: ", VV_XD, |
| "Oper->allocJitValue( this, Bldr, Oper->getType(), Oper->getLen(), 1 )\n" ); |
| Oper->allocJitValue( this, Bldr, Oper->getType(), Oper->getLen(), 1 ) ; |
| } |
| } |
| |
| #if NExprDbgLvl >= VV_BD |
| for (Int32 iii = 0; iii < opList.entries(); iii++ ) |
| { |
| DPT2( "VV9B006b: ", VV_XD, "In OPDATA_*, opList[%d] = %p\n", |
| iii, opList[iii] ); |
| DPT1( "VV9B006c: ", VV_XD, |
| "Details of opList[%d] *BEFORE setupClauseOperand* are:\n", |
| iii ); |
| PCodeOperand *PCOp = opList[iii]; |
| if (!PCOp) continue; |
| |
| DPT6( "VV9B006d: ", VV_XD, |
| "stackIndex_ = %d, offset_ = %d, len_=%d, operandType_=%d, nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| } |
| |
| for ( Int32 mmm = 0; (mmm <= index) && (mmm < opList.entries()); mmm++) |
| { |
| DPT2( "VV9B007: ", VV_XD, "OPDATA_* AFTER opData[%d] = %p\n", |
| mmm, opData[mmm] ); |
| if ( opData[mmm] ) |
| { |
| DPT1( "VV9B008: ", VV_XD, |
| "Details of opData[%d] *AFTER setupClauseOperand() are:\n", |
| mmm ); |
| |
| PCodeOperand *PCOp = opData[mmm]; |
| if (!PCOp) continue; |
| |
| DPT6( "VV9B009: ", VV_XD, |
| "stackIndex_ = %d, offset_ = %d, len_=%d, operandType_=%d, nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| } |
| } |
| #endif /* NExprDbgLvl >= VV_BD */ |
| |
| break; |
| } |
| |
| case PCIT::CLAUSE_EVAL: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, resIRtype ; |
| |
| //// jit_label_t doneLabel = jit_label_undefined; |
| //// jit_label_t trueLabel = jit_label_undefined; |
| //// jit_label_t falseLabel = jit_label_undefined; |
| //// jit_label_t nullLabel = jit_label_undefined; |
| |
| p_IR_block_t doneLabel = BasicBlock::Create( LLContxt, "ClauseEvalDoneBlk" ); |
| |
| DPT1( "VV9B101: ", VV_XD, "doneLabel = %p\n", doneLabel ); |
| |
| // on 64-bit the clause pointer is in code[1] and code[2] |
| ex_clause* clause = (ex_clause*)*(Long*)&(PCInst->code[1]); |
| NABoolean processNulls = PCInst->code[1 + PCODEBINARIES_PER_PTR]; |
| |
| #if NExprDbgLvl >= VV_BD |
| for (Int32 iii = 0; iii < 3; iii++ ) |
| { |
| DPT2( "VV9B103: ", VV_XD, "In CLAUSE_EVAL opDataNulls[%d] = %p\n", |
| iii, opDataNulls[iii] ); |
| if ( opDataNulls[iii] ) |
| { |
| DPT1( "VV9B104: ", VV_XD, |
| "Details of opDataNulls[%d] *AT Start OF CLAUSE_EVAL* are:\n", iii ); |
| |
| PCodeOperand *PCOp = opDataNulls[iii]; |
| |
| DPT6( "VV9B105: ", VV_XD, |
| "stackIndex_ = %d, offset_ = %d, len_=%d, operandType_=%d, nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| } |
| } |
| |
| for (Int32 jjj = 0; jjj < 3; jjj++ ) |
| { |
| DPT2( "VV9B110: ", VV_XD, "In CLAUSE_EVAL opDataVals[%d] = %p\n", |
| jjj, opDataVals[jjj] ); |
| if ( opDataVals[jjj] ) |
| { |
| DPT1( "VV9B114: ", VV_XD, |
| "Details of opDataVals[%d] *AT Start OF CLAUSE_EVAL* are:\n", jjj ); |
| |
| PCodeOperand *PCOp = opDataVals[jjj]; |
| |
| DPT6( "VV9B115: ", VV_XD, |
| "stackIndex_ = %d, offset_ = %d, len_=%d, operandType_=%d, nullBitIdx=%d, CJV=%p\n", |
| PCOp->getStackIndex(), PCOp->getOffset(), PCOp->getLen(), |
| PCOp->getType(), PCOp->getNullBitIndex(), PCOp->getCurrJitVal() ); |
| } |
| } |
| #endif /* NExprDbgLvl >= VV_BD */ |
| |
| switch (clause->getClassID()) { |
| case ex_clause::AGGR_MIN_MAX_ID: |
| { |
| DPT0( "VV9B120: ", VV_VD, |
| "CLAUSE_EVAL - found ClassID = AGGR_MIN_MAX_ID \n"); |
| // |
| // Format: |
| // |
| // attr[0] - Aggregate |
| // attr[1] - Column |
| // attr[2] - Comparison result |
| // |
| |
| // First branch away if comp result indicates no update needed. |
| // Note, since this check is always made, the jit value from the |
| // null-check can be used outside of the CLAUSE_EVAL. |
| src2 = opDataVals[2]; |
| //// src2JitVal = src2->getJitValue(this, f, jit_type_int, block); |
| src2JitVal = src2->getJitValue(this, Bldr, int32Ty_ , PCBlk); |
| |
| //// jit_insn_branch_if_not(f, src2JitVal, &doneLabel); |
| IR_insn_branch_if_zero( Bldr, src2JitVal, &doneLabel ); |
| |
| // We need to copy over source into aggregate. First take care of |
| // the null indicator if the aggregate is nullable. |
| if (clause->getOperand(0)->getNullFlag()) { |
| // If column is nullable too, then we need to check it. If it's |
| // NULL, we don't do anything. |
| |
| if (clause->getOperand(1)->getNullFlag()) { |
| src1 = opDataNulls[1]; |
| |
| //// src1JitVal = |
| //// src1->getJitValue(this, f, src1->getJitType(), block, |
| //// NULL, TRUE /* no assign jit val */); |
| |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk, |
| NULL, TRUE /* no assign */); |
| |
| //// jit_insn_branch_if(f, src1JitVal, &doneLabel); |
| IR_insn_branch_if_not_zero( Bldr, src1JitVal, &doneLabel ); |
| } |
| |
| // Null out the null indicator for the aggregate. Based on the |
| // current code, the null indicator for the aggregate is always |
| // in exploded format, so assert that here and then simplify |
| // code generation. |
| assert(!opDataNulls[0]->forAlignedFormat()); |
| |
| //// opDataNulls[0]->setJitValue(this, f, zeroJitVal16, block, TRUE); |
| opDataNulls[0]->setJitValue( this, Bldr, IR_Const_16bit_0_, |
| PCBlk, TRUE); |
| } |
| |
| // Now we have to handle moving the data over from column to aggr. |
| res = opDataVals[0]; |
| src1 = opDataVals[1]; |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), |
| //// block, NULL, TRUE /* no assign */); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue( this, Bldr, src1IRtype, PCBlk, |
| NULL, TRUE /* no assign */); |
| |
| if (res->isVarchar()) |
| { |
| // The following code was taken from MOVE_MATTR5_MATTR5, but |
| // re-formatted here. |
| jit_type_t vcType; |
| jit_value_t vcLenJitVal; |
| |
| if (src1->getVcIndicatorLen() == 2) { |
| //// vcType = jit_type_ushort; |
| vcType = int16Ty_ ; |
| |
| //// vcLenJitVal=jit_value_create_nint_constant(f, jit_type_int,2); |
| vcLenJitVal = ConstantInt::get( int32Ty_, 2 ); |
| } |
| else { |
| //// vcType = jit_type_uint; |
| vcType = int32Ty_ ; |
| |
| //// vcLenJitVal=jit_value_create_nint_constant(f, jit_type_int,4); |
| vcLenJitVal = ConstantInt::get( int32Ty_, 4 ); |
| } |
| |
| //// resJitVal = res->getJitValue(this, f, res->getJitType(), block, |
| //// NULL, TRUE /* no assign */); |
| |
| resIRtype = res->getJitType( this ); |
| resJitVal = res->getJitValue(this, Bldr, resIRtype, PCBlk, |
| NULL, TRUE /* no assign */); |
| |
| //// jit_insn_store(f, tRes, resJitVal); |
| //// jit_insn_store(f, tSrc1, src1JitVal); |
| |
| //// jit_value_t srcLen = |
| //// jit_insn_load_relative(f, src1JitVal, 0, vcType); |
| |
| jit_value_t srcLen = IR_LoadRelativeWithType( Bldr, |
| src1JitVal, 0, vcType ); |
| |
| //// srcLen = jit_insn_add(f, srcLen, vcLenJitVal); |
| |
| DPT0( "VV9B130: ", VV_VD, |
| "srcLen = Bldr->CreateAdd( srcLen , vcLenJitVal , 'IntAdd' )\n"); |
| srcLen = Bldr->CreateAdd( srcLen , vcLenJitVal , "IntAdd" ); |
| |
| //// genUnalignedMemcpy(f, tRes, tSrc1, srcLen); |
| genUnalignedMemcpy( Bldr, resJitVal, src1JitVal, srcLen ); |
| } |
| else |
| { |
| //// res->storeJitValue(this, f, res->getJitType(),src1JitVal, |
| //// block, NULL, TRUE); |
| jit_type_t resIRtype = res->getJitType( this ) ; |
| res->storeJitValue(this, Bldr, resIRtype, |
| src1JitVal, PCBlk, NULL, TRUE ); |
| } |
| |
| // Reached the end point |
| //// jit_insn_label(f, &doneLabel); |
| |
| DPT1( "VV9B134: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); // Must complete the current block |
| |
| DPT1( "VV9B136: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( doneLabel = %p )\n", doneLabel ); |
| ExpFn->getBasicBlockList().push_back( doneLabel ); |
| |
| DPT1( "VV9B138: ", VV_VD, |
| "Bldr->SetInsertPoint( doneLabel = %p )\n", doneLabel ); |
| Bldr->SetInsertPoint( doneLabel ); |
| |
| break; |
| } |
| |
| case ex_clause::COMP_TYPE: |
| { |
| DPT0( "VV9B200: ", VV_VD, |
| "CLAUSE_EVAL - found ClassID = COMP_TYPE \n"); |
| |
| p_IR_block_t trueLabel = BasicBlock::Create( LLContxt, "ClauseEvalTrueBlk" ); |
| p_IR_block_t falseLabel = BasicBlock::Create( LLContxt, "ClauseEvalFalseBlk" ); |
| p_IR_block_t nullLabel = BasicBlock::Create( LLContxt, "ClauseEvalNullBlk" ); |
| |
| DPT3( "VV9B201: ", VV_VD, |
| "trueLabel = %p, falseLabel = %p, nullLabel = %p\n", |
| trueLabel, falseLabel, nullLabel ); |
| |
| switch (((ex_comp_clause*)clause)->getInstruction()) { |
| case NE_DATETIME_DATETIME: |
| case EQ_DATETIME_DATETIME: |
| case LT_DATETIME_DATETIME: |
| case GT_DATETIME_DATETIME: |
| case LE_DATETIME_DATETIME: |
| case GE_DATETIME_DATETIME: |
| { |
| DPT0( "VV9B210: ", VV_VD, |
| "CLAUSE_EVAL - COMP_TYPE - found DATETIME case index\n" ); |
| jit_value_t year1, year2; |
| |
| res = opDataVals[0]; |
| src1 = opDataVals[1]; |
| src2 = opDataVals[2]; |
| |
| DPT3( "VV9B211: ", VV_XD, |
| "COMP_TYPE - res = %p, src1 = %p, src2 = %p \n", |
| res, src1, src2 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, |
| //// block, NULL); |
| src1JitVal = src1->getJitValue(this, Bldr, int1PtrTy_, |
| PCBlk, NULL ); |
| |
| //// src2JitVal = src2->getJitValue(this, f, jit_type_void_ptr, |
| //// block, NULL); |
| src2JitVal = src2->getJitValue(this, Bldr, int1PtrTy_, |
| PCBlk, NULL ); |
| DPT2( "VV9B212: ", VV_XD, |
| "COMP_TYPE - src1JitVal at %p, src2JitVal at %p \n", |
| src1JitVal, src2JitVal ); |
| if (processNulls) |
| { |
| PCodeOperand* nullOp; |
| jit_value_t nullJitVal; |
| |
| if (clause->getOperand(1)->getNullFlag()) |
| { |
| DPT1( "VV9B213: ", VV_XD, |
| "COMP_TYPE - opDataNulls[1] == %p\n", |
| opDataNulls[1] ); |
| |
| nullOp = opDataNulls[1]; |
| //// nullJitVal = |
| //// nullOp->getJitValue(this, f, nullOp->getJitType(), block, |
| //// NULL, TRUE /* no assign jit val */); |
| |
| nullJitVal = nullOp->getJitValue(this, Bldr, |
| nullOp->getJitType( this ), |
| PCBlk, NULL, TRUE /* no assign */); |
| |
| DPT1( "VV9B214: ", VV_XD, |
| "COMP_TYPE - nullJitVal at %p\n", nullJitVal ); |
| |
| //// jit_insn_branch_if(f, nullJitVal, &nullLabel); |
| |
| DPT1( "VV9B215: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, nullJitVal, &nullLabel = %p )\n", nullLabel ); |
| IR_insn_branch_if_not_zero( Bldr, nullJitVal, &nullLabel ); |
| } |
| |
| if (clause->getOperand(2)->getNullFlag()) { |
| nullOp = opDataNulls[2]; |
| |
| DPT1( "VV9B216: ", VV_XD, |
| "COMP_TYPE-opDataNulls[2] == %p\n", opDataNulls[2]); |
| |
| //// nullJitVal = |
| //// nullOp->getJitValue(this, f, nullOp->getJitType(), block, |
| //// NULL, TRUE /* no assign jit val */); |
| nullJitVal = nullOp->getJitValue(this, Bldr, |
| nullOp->getJitType( this ), |
| PCBlk, NULL, TRUE /* no assign */); |
| |
| DPT1( "VV9B217: ", VV_XD, |
| "COMP_TYPE-nullJitVal at %p\n", nullJitVal ); |
| |
| //// jit_insn_branch_if(f, nullJitVal, &nullLabel); |
| |
| DPT1( "VV9B218: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, nullJitVal, &nullLabel = %p )\n", nullLabel ); |
| IR_insn_branch_if_not_zero( Bldr, nullJitVal, &nullLabel ); |
| } |
| } |
| |
| long dtCode = |
| ((ExpDatetime*)(clause->getOperand(1)))->getPrecision(); |
| |
| switch (dtCode) |
| { |
| case REC_DTCODE_TIME: |
| case REC_DTCODE_DATE: |
| case REC_DTCODE_TIMESTAMP: |
| { |
| // Boolean used to indicate whether branch should go to |
| // true block or not. Assume "not" by default. |
| NABoolean dumpTrueBlockFirst = TRUE; // May change later |
| |
| Int32 size = (clause->getOperand(1))->getLength(); |
| |
| // Cycle through each field in the date-related struct. |
| Int32 typeSize = 0; |
| for (i=0; i < size; i += typeSize) |
| { |
| jit_type_t type; |
| |
| // Are we getting the fractional seconds? |
| if ((i == size-4) && (dtCode == REC_DTCODE_TIMESTAMP)) { |
| //// type = jit_type_uint; |
| type = int32Ty_ ; |
| typeSize = 4; |
| } |
| // Are we getting the year? |
| else if ((i==0) && (dtCode != REC_DTCODE_TIME)) { |
| //// type = jit_type_ushort; |
| type = int16Ty_ ; |
| typeSize = 2; |
| } |
| // We're just getting some particular byte field |
| else { |
| //// type = jit_type_ubyte; |
| type = int8Ty_ ; |
| typeSize = 1; |
| } |
| |
| // Get the fields from both sources. |
| //// year1 = jit_insn_load_relative(f, src1JitVal, i, type); |
| year1 = IR_LoadRelativeWithType( Bldr, |
| src1JitVal, i, type ); |
| |
| //// year2 = jit_insn_load_relative(f, src2JitVal, i, type); |
| year2 = IR_LoadRelativeWithType( Bldr, |
| src2JitVal, i, type ); |
| |
| DPT2( "VV9B219: ", VV_XD, |
| "COMP_TYPE-year1 at %p, year2 at %p\n", |
| year1, year2 ); |
| |
| // Depending on the comparison being performed, generate |
| // 1 (or 2) compares and branches. Also, based on the |
| // comparison, the fall-through may be the "true" block, |
| // or it may be the "false" block - default is TRUE. |
| |
| switch (((ex_comp_clause*)clause)->getInstruction()) { |
| case NE_DATETIME_DATETIME: |
| //// resJitVal = jit_insn_ne(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_NE, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| //// jit_insn_branch_if(f, resJitVal, &trueLabel); |
| |
| DPT1( "VV9B220: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel = %p)\n", trueLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel ); |
| |
| dumpTrueBlockFirst = FALSE; |
| break; |
| case EQ_DATETIME_DATETIME: |
| //// resJitVal = jit_insn_ne(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_EQ, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &falseLabel); |
| |
| DPT1( "VV9B222: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel = %p )\n", falseLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel ); |
| |
| break; |
| case LT_DATETIME_DATETIME: |
| //// resJitVal = jit_insn_lt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_ULT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &trueLabel); |
| |
| DPT1( "VV9B224: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel = %p )\n", trueLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel ); |
| |
| //// resJitVal = jit_insn_gt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_UGT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &falseLabel); |
| |
| DPT1( "VV9B226: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel = %p )\n", falseLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel ); |
| |
| dumpTrueBlockFirst = FALSE; |
| break; |
| case GT_DATETIME_DATETIME: |
| //// resJitVal = jit_insn_gt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_UGT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &trueLabel); |
| |
| DPT1( "VV9B230: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel = %p )\n", trueLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel ); |
| |
| //// resJitVal = jit_insn_lt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_ULT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &falseLabel); |
| |
| DPT1( "VV9B232: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel = %p )\n", falseLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel ); |
| |
| dumpTrueBlockFirst = FALSE; |
| break; |
| case LE_DATETIME_DATETIME: |
| //// resJitVal = jit_insn_lt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_ULT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &trueLabel); |
| |
| DPT1( "VV9B234: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel = %p )\n", trueLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel ); |
| |
| //// resJitVal = jit_insn_gt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_UGT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &falseLabel); |
| |
| DPT1( "VV9B236: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel = %p )\n", falseLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel ); |
| |
| break; |
| case GE_DATETIME_DATETIME: |
| //// resJitVal = jit_insn_gt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_UGT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &trueLabel); |
| |
| DPT1( "VV9B238: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel = %p )\n", trueLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &trueLabel ); |
| |
| //// resJitVal = jit_insn_lt(f, year1, year2); |
| resJitVal = jitGenCompare( Bldr, IntCompare_ULT, |
| year1, year2, |
| IR_Const_1_ , |
| IR_Const_0_ ); |
| |
| //// jit_insn_branch_if(f, resJitVal, &falseLabel); |
| |
| DPT1( "VV9B240: ", VV_XD, |
| "IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel = %p )\n", falseLabel); |
| IR_insn_branch_if_not_zero( Bldr, resJitVal, &falseLabel ); |
| |
| break; |
| } |
| } |
| |
| if (!dumpTrueBlockFirst) |
| { |
| DPT1( "VV9B250: ", VV_VD, |
| "Bldr->CreateBr( falseLabel = %p )\n", falseLabel ); |
| Bldr->CreateBr( falseLabel ); // Must complete the current block |
| |
| // False label first. |
| //// jit_insn_label(f, &falseLabel); |
| |
| DPT1( "VV9B251: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( falseLabel = %p )\n", falseLabel ); |
| ExpFn->getBasicBlockList().push_back( falseLabel ); |
| |
| DPT1( "VV9B252: ", VV_VD, |
| "Bldr->SetInsertPoint( falseLabel = %p )\n", falseLabel ); |
| Bldr->SetInsertPoint( falseLabel ); |
| |
| //// res->storeJitValue(this, f, jit_type_int, zeroJitVal_, |
| //// block); |
| DPT0( "VV9B253: ", VV_XD, |
| "res->storeJitValue(this, Bldr, int32Ty_, IR_Const_0_, PCBlk) \n" ); |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_0_, |
| PCBlk ); |
| //// jit_insn_branch(f, &doneLabel); |
| |
| DPT1( "VV9B254: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); |
| |
| // True label next. |
| //// jit_insn_label(f, &trueLabel); |
| |
| DPT1( "VV9B256: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( trueLabel = %p )\n", trueLabel ); |
| ExpFn->getBasicBlockList().push_back( trueLabel ); |
| |
| DPT1( "VV9B258: ", VV_VD, |
| "Bldr->SetInsertPoint( trueLabel = %p )\n", trueLabel ); |
| Bldr->SetInsertPoint( trueLabel ); |
| |
| //// res->storeJitValue(this, f, jit_type_int, oneJitVal_, |
| //// block); |
| DPT0( "VV9B259: ", VV_XD, |
| "res->storeJitValue(this, Bldr, int32Ty_, IR_Const_1_, PCBlk )\n" ); |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_1_, |
| PCBlk ); |
| //// jit_insn_branch(f, &doneLabel); |
| |
| DPT1( "VV9B260: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); |
| } |
| else { |
| DPT1( "VV9B261: ", VV_VD, |
| "Bldr->CreateBr( trueLabel = %p )\n", trueLabel ); |
| Bldr->CreateBr( trueLabel ); // Must complete the current block |
| |
| // True label first. |
| //// jit_insn_label(f, &trueLabel); |
| |
| DPT1( "VV9B262: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( trueLabel = %p )\n", trueLabel ); |
| ExpFn->getBasicBlockList().push_back( trueLabel ); |
| |
| DPT1( "VV9B264: ", VV_VD, |
| "Bldr->SetInsertPoint( trueLabel = %p )\n", trueLabel ); |
| Bldr->SetInsertPoint( trueLabel ); |
| |
| //// res->storeJitValue(this, f, jit_type_int, oneJitVal_, |
| //// block); |
| DPT0( "VV9B265: ", VV_XD, |
| "res->storeJitValue(this, Bldr, int32Ty_, IR_Const_1_, ...)\n" ); |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_1_, |
| PCBlk ); |
| //// jit_insn_branch(f, &doneLabel); |
| |
| DPT1( "VV9B266: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); |
| |
| // False label next. |
| //// jit_insn_label(f, &falseLabel); |
| |
| DPT1( "VV9B268: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( falseLabel = %p )\n", falseLabel ); |
| ExpFn->getBasicBlockList().push_back( falseLabel ); |
| |
| DPT1( "VV9B270: ", VV_VD, |
| "Bldr->SetInsertPoint( falseLabel = %p )\n", falseLabel ); |
| Bldr->SetInsertPoint( falseLabel ); |
| |
| //// res->storeJitValue(this, f, jit_type_int, zeroJitVal_, |
| //// block); |
| |
| DPT0( "VV9B271: ", VV_XD, |
| "res->storeJitValue(this, Bldr, int32Ty_, IR_Const_0_, PCBlk )\n" ); |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_0_, |
| PCBlk ); |
| //// jit_insn_branch(f, &doneLabel); |
| |
| DPT1( "VV9B272: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); |
| } |
| |
| // Null label last. |
| //// jit_insn_label(f, &nullLabel); |
| |
| DPT1( "VV9B274: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( nullLabel = %p )\n", nullLabel ); |
| ExpFn->getBasicBlockList().push_back( nullLabel ); |
| |
| DPT1( "VV9B276: ", VV_VD, |
| "Bldr->SetInsertPoint( nullLabel = %p )\n", nullLabel ); |
| Bldr->SetInsertPoint( nullLabel ); |
| |
| //// res->storeJitValue(this,f,jit_type_int,neg1JitVal_,block); |
| |
| DPT0( "VV9B277: ", VV_XD, |
| "res->storeJitValue(this, Bldr, int32Ty_, IR_Const_neg1_, PCBlk )\n" ); |
| res->storeJitValue(this, Bldr, int32Ty_, IR_Const_neg1_, |
| PCBlk ); |
| |
| //// jit_insn_label(f, &doneLabel); |
| |
| DPT1( "VV9B278: ", VV_VD, |
| "Bldr->CreateBr( doneLabel = %p )\n", doneLabel ); |
| Bldr->CreateBr( doneLabel ); // Must complete the current block |
| |
| DPT1( "VV9B279: ", VV_VD, |
| "ExpFn->getBasicBlockList().push_back( doneLabel = %p )\n", doneLabel ); |
| ExpFn->getBasicBlockList().push_back( doneLabel ); |
| |
| DPT1( "VV9B280: ", VV_VD, |
| "Bldr->SetInsertPoint( doneLabel = %p )\n", doneLabel ); |
| Bldr->SetInsertPoint( doneLabel ); |
| |
| break; |
| } |
| |
| default: |
| assert(FALSE); |
| } |
| break; |
| } |
| } |
| |
| break; |
| } |
| } |
| |
| // Clear out opData for subsequent use. |
| str_pad((char*)opData, |
| (3*ex_clause::MAX_OPERANDS)*sizeof(PCodeOperand*), 0); |
| |
| break; |
| } |
| |
| case PCIT::SUM_MBIN32S_MBIN32S: |
| case PCIT::SUM_MBIN64S_MBIN64S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| |
| res = PCInst->getWOps()[0]; |
| src1 = res; /* same as write operand */ |
| src2 = PCInst->getROps()[1]; |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| src1JitVal = src1->getJitValue(this, Bldr, src1->getJitType(this), PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), PCBlk); |
| src2JitVal = src2->getJitValue(this, Bldr, src2->getJitType(this), PCBlk); |
| |
| #if NExprDbgLvl >= VV_VD |
| if ( src1->isConst() ) |
| DPT0( "VV9C005: ", VV_VD, |
| "case PCIT::SUM_MB... src1 is a CONSTANT !\n" ); |
| |
| if ( src2->isConst() ) |
| DPT0( "VV9C006: ", VV_VD, |
| "case PCIT::SUM_MB... src2 is a CONSTANT !\n" ); |
| #endif |
| |
| //// resJitVal = jit_insn_add(f, src1JitVal, src2JitVal); |
| |
| DPT0( "VV9C010: ", VV_VD, |
| "resJitVal = Bldr->CreateAdd( src1JitVal , src2JitVal , 'IntAdd' )\n" ); |
| resJitVal = Bldr->CreateAdd( src1JitVal , src2JitVal , "IntAdd" ); |
| |
| //// res->setJitValue(this, f, resJitVal, PCBlk); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if (opc == PCIT::SUM_MBIN64S_MBIN32S) |
| src2->clearJitValues(this); |
| |
| break; |
| } |
| |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S: |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype, resIRtype ; |
| |
| res = PCInst->getWOps()[0]; |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| resIRtype = res->getJitType( this ); |
| |
| Int32 src1Width = src1IRtype->getIntegerBitWidth(); |
| Int32 src2Width = src2IRtype->getIntegerBitWidth(); |
| Int32 resWidth = resIRtype->getIntegerBitWidth(); |
| |
| if ( src1Width < resWidth ) |
| { |
| DPT0( "VV9C100: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt( src1JitVal, (IntegerType *)resIRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)resIRtype, "SExt" ) ; |
| } |
| if ( src2Width < resWidth ) |
| { |
| DPT0( "VV9C105: ", VV_VD, |
| "src2JitVal = Bldr->CreateSExt( src2JitVal, (IntegerType *)resIRtype, 'SExt' )\n" ); |
| src2JitVal = Bldr->CreateSExt( src2JitVal, |
| (IntegerType *)resIRtype, "SExt" ) ; |
| } |
| |
| //// resJitVal = jit_insn_add(f, src1JitVal, src2JitVal); |
| |
| DPT0( "VV9C110: ", VV_VD, |
| "resJitVal = Bldr->CreateAdd( src1JitVal , src2JitVal , 'IntAdd' )\n" ); |
| resJitVal = Bldr->CreateAdd( src1JitVal , src2JitVal , "IntAdd" ); |
| |
| //// res->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| //// if (opc == PCIT::ADD_MFLT64_MFLT64_MFLT64) |
| //// jitProcessFloatExceptionCheck(f, res, &errorJitLabel, block); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if (opc == PCIT::ADD_MBIN64S_MBIN32S_MBIN64S) |
| src1->clearJitValues(this); |
| |
| break; |
| } |
| |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::SUB_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S: |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN16S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype, resIRtype ; |
| |
| res = PCInst->getWOps()[0]; |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| resIRtype = res->getJitType( this ); |
| |
| Int32 src1Width = src1IRtype->getIntegerBitWidth(); |
| Int32 src2Width = src2IRtype->getIntegerBitWidth(); |
| Int32 resWidth = resIRtype->getIntegerBitWidth(); |
| |
| if ( src1Width < resWidth ) |
| { |
| DPT0( "VV9C200: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt( src1JitVal, (IntegerType *)resIRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)resIRtype, "SExt" ) ; |
| } |
| if ( src2Width < resWidth ) |
| { |
| DPT0( "VV9C205: ", VV_VD, |
| "src2JitVal = Bldr->CreateSExt( src2JitVal, (IntegerType *)resIRtype, 'SExt' )\n" ); |
| src2JitVal = Bldr->CreateSExt( src2JitVal, |
| (IntegerType *)resIRtype, "SExt" ) ; |
| } |
| |
| //// resJitVal = jit_insn_sub(f, src1JitVal, src2JitVal); |
| |
| DPT0( "VV9C210: ", VV_VD, |
| "resJitVal = Bldr->CreateSub( src1JitVal , src2JitVal , 'IntSub' )\n" ); |
| resJitVal = Bldr->CreateSub( src1JitVal , src2JitVal , "IntSub" ); |
| |
| //// res->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| //// if (opc == PCIT::SUB_MFLT64_MFLT64_MFLT64) |
| //// jitProcessFloatExceptionCheck(f, res, &errorJitLabel, block); |
| |
| //// // No opt support for this instruction |
| //// if (opc == PCIT::SUB_MBIN64S_MBIN64S_MBIN64S) |
| //// lowerOptLevel = TRUE; |
| |
| |
| break; |
| } |
| |
| case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S: |
| case PCIT::MUL_MBIN64S_MBIN32S_MBIN32S: |
| case PCIT::MUL_MBIN64S_MBIN16S_MBIN32S: |
| case PCIT::MUL_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S: |
| { |
| PCodeOperand *src1, *src2, *res ; |
| jit_value_t src1JitVal, src2JitVal, resJitVal ; |
| jit_type_t src1IRtype, src2IRtype, resIRtype ; |
| |
| res = PCInst->getWOps()[0]; |
| src1 = PCInst->getROps()[0]; |
| src2 = PCInst->getROps()[1]; |
| PRINT_DETAILS_OF_WROp( 0, res ); |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| PRINT_DETAILS_OF_RDOp( 1, src2 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1IRtype = src1->getJitType( this ); |
| src1JitVal = src1->getJitValue(this, Bldr, src1IRtype, PCBlk); |
| |
| //// src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| src2IRtype = src2->getJitType( this ); |
| src2JitVal = src2->getJitValue(this, Bldr, src2IRtype, PCBlk); |
| |
| resIRtype = res->getJitType( this ); |
| |
| Int32 src1Width = src1IRtype->getIntegerBitWidth(); |
| Int32 src2Width = src2IRtype->getIntegerBitWidth(); |
| Int32 resWidth = resIRtype->getIntegerBitWidth(); |
| |
| if ( src1Width < resWidth ) |
| { |
| DPT0( "VV9C300: ", VV_VD, |
| "src1JitVal = Bldr->CreateSExt( src1JitVal, (IntegerType *)resIRtype, 'SExt' )\n" ); |
| src1JitVal = Bldr->CreateSExt( src1JitVal, |
| (IntegerType *)resIRtype, "SExt" ) ; |
| } |
| if ( src2Width < resWidth ) |
| { |
| DPT0( "VV9C305: ", VV_VD, |
| "src2JitVal = Bldr->CreateSExt( src2JitVal, (IntegerType *)resIRtype, 'SExt' )\n" ); |
| src2JitVal = Bldr->CreateSExt( src2JitVal, |
| (IntegerType *)resIRtype, "SExt" ) ; |
| } |
| |
| //// resJitVal = jit_insn_mul(f, src1JitVal, src2JitVal); |
| |
| DPT0( "VV9C310: ", VV_VD, |
| "resJitVal = Bldr->CreateMul( src1JitVal , src2JitVal , 'IntMul' )\n" ); |
| resJitVal = Bldr->CreateMul( src1JitVal , src2JitVal , "IntMul" ); |
| |
| //// res->setJitValue(this, f, resJitVal, block); |
| res->setJitValue(this, Bldr, resJitVal, PCBlk); |
| |
| |
| //// if (opc == PCIT::MUL_MFLT64_MFLT64_MFLT64) |
| //// jitProcessFloatExceptionCheck(f, res, &errorJitLabel, block); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN32S: |
| { |
| PCodeOperand *src1 ; |
| jit_value_t src1JitVal ; |
| |
| // RETURN instruction must follow |
| assert (PCInst->next && (PCInst->next->code[0] == PCIT::RETURN)); |
| |
| //// jit_label_t l1 = jit_label_undefined; |
| //// jit_label_t l2 = jit_label_undefined; |
| |
| src1 = PCInst->getROps()[0]; |
| PRINT_DETAILS_OF_RDOp( 0, src1 ); |
| |
| DPT1( "VV9D002: ", VV_XD, |
| "Processing MOVE_MBIN32S - 1, src1 = PCodeOp at %p\n", src1 ); |
| |
| //// src1JitVal = src1->getJitValue(this, f, src1->getJitType(), PCBlk); |
| src1JitVal = src1->getJitValue(this, Bldr, src1->getJitType(this), PCBlk); |
| |
| DPT1( "VV9D003: ", VV_XD, |
| "Processing MOVE_MBIN32S - 1, src1JitVal at %p\n", src1JitVal ); |
| |
| //// jit_value_t t1 = jit_insn_eq(f, src1JitVal, oneJitVal_); |
| //// jit_insn_branch_if(f, t1, &l1); |
| //// jit_insn_label(f, &l2); |
| //// jit_insn_return(f, fJitVal_); |
| //// jit_insn_label(f, &l1); |
| //// jit_insn_return(f, tJitVal_); |
| |
| jit_value_t Rslt = jitGenCompare( Bldr, IntCompare_EQ, |
| src1JitVal, IR_Const_1_ , |
| IR_Const_TRUE_, IR_Const_FALSE_ ); |
| |
| DPT0( "VV9D005: ", VV_VD, "returned from jitGenCompare()\n"); |
| |
| DPT0( "VV9D010: ", VV_VD, |
| "Bldr->CreateRet( Rslt )\n" ); |
| Bldr->CreateRet( Rslt ); |
| |
| justGeneratedRET = TRUE; |
| break; |
| } |
| |
| case PCIT::RETURN_IBIN32S: |
| { |
| jit_value_t resJitVal ; |
| |
| // if (inst->code[1] == 1) jit_insn_return(f, tJitVal_); |
| // else jit_insn_return(f, fJitVal_); |
| |
| if (PCInst->code[1] == 1) |
| resJitVal = IR_Const_TRUE_ ; |
| else |
| resJitVal = IR_Const_FALSE_ ; |
| |
| DPT0( "VV9E010: ", VV_VD, |
| "Bldr->CreateRet( resJitVal )\n"); |
| Bldr->CreateRet( resJitVal ); |
| |
| justGeneratedRET = TRUE; |
| break; |
| } |
| |
| case PCIT::RETURN: |
| { |
| DPT0( "VV9F001: ", VV_VD, |
| "Bldr->CreateRet( IR_Const_OK_ )\n"); |
| Bldr->CreateRet( IR_Const_OK_ ); |
| |
| justGeneratedRET = TRUE; |
| break; |
| } |
| } // end of switch (opc) |
| |
| #if NExprDbgLvl >= VV_VD |
| if ( PCInst ) |
| DPT2( "VVzz000: ", VV_VD, |
| "At end of Main Loop : PCInst at %p, PCInst->next = %p \n", |
| PCInst, PCInst->next ); |
| |
| if ( PCInst && PCInst->next ) |
| DPT2( "VVzz001: ", VV_VD, |
| "At end of Main Loop: next at %p has opc == %d\n", |
| PCInst->next , (int) PCInst->next->getOpcode()); |
| #endif |
| |
| } ENDFE_INST_IN_BLOCK |
| |
| if ( ( opc != PCIT::BRANCH ) && // if last one was not a BRANCH |
| ( opc != PCIT::RETURN ) && // and was not a RETURN |
| ( opc != PCIT::RETURN_IBIN32S ) && // of any sort, and if |
| ( (PCBlkIndex + 1) < physBlockList.entries() ) // there are more blocks |
| ) |
| { |
| PCodeBlock* nxtBlock = physBlockList[ PCBlkIndex + 1 ]; |
| assert( nxtBlock ); |
| |
| // |
| // IMPORTANT NOTE: |
| // LLVM's verifyFunction() routine absolutely requires that *every* |
| // llvm::BasicBlock be terminated with either a Branch or a Return. |
| // If there is a BasicBlock that is not terminated, either |
| // verifyFunction() will complain or, worse yet, it may simply |
| // never return (because it calls 'exit' instead.) |
| // So here we "complete" the current block. |
| // |
| p_IR_block_t TgtBlk = *( nxtBlock->getJitBlkLbl() ); |
| |
| DPT1( "VVzzz00: ", VV_VD, |
| "Bldr->CreateBr( TgtBlk = %p )\n", TgtBlk ); |
| Bldr->CreateBr( TgtBlk ); |
| } |
| |
| DPT0( "VVzzz09: ", VV_VD, "Finished the FOREACH_INST_IN_BLOCK loop\n"); |
| |
| } // END: for (PCBlkIndex=0; ... |
| |
| DPT0( "VVzzz10: ", VV_VD, "FINISHED the MAIN loop\n"); |
| |
| if ( justGeneratedRET == FALSE && justHandledUnconditionBranch == FALSE ) |
| { |
| // |
| // The last block should *always* end with a Return or Unconditional Br. |
| // |
| DPT0( "VVzzz12: ", VV_VD, |
| "Bldr->CreateRet( IR_Const_OK_ )\n"); |
| Bldr->CreateRet( IR_Const_OK_ ); |
| } |
| |
| DPT0( "VVzzz99: ", VV_BD, "GOT PAST the final CreateRet\n"); |
| |
| #if NExprDbgLvl >= VV_BD |
| if ( NExprDbgLvl_ >= VV_BD ) |
| std::cout << std::flush ; // Flush anything in the data buffer |
| #endif |
| |
| std::stringstream myBuffer; |
| std::streambuf * old = std::cerr.rdbuf( myBuffer.rdbuf() ); |
| |
| #if NExprDbgLvl >= VV_BD |
| if ( NExprDbgLvl_ >= VV_BD ) |
| { |
| std::cerr << std::flush ; // Flush anything in the data buffer |
| std::cerr << "QRST\n" ; // Put out marker so we can see that we got here |
| |
| DPT0( "VVzzz08: ", VV_BD, "CALLING verifyFunction() !!! \n"); |
| std::cerr << std::flush ; // Flush anything in the data buffer |
| } |
| #endif // NExprDbgLvl >= VV_BD |
| |
| |
| // LLVM Requires this function be called! |
| //NABoolean VF_rtn = llvm::verifyFunction(*ExpFn) ; |
| NABoolean VF_rtn = llvm::verifyFunction(*ExpFn, PrintMessageAction) ; |
| |
| |
| #if NExprDbgLvl >= VV_BD |
| if ( NExprDbgLvl_ >= VV_BD ) |
| { |
| DPT0( "VVzzz10: ", VV_VD, "RETURNED FROM verifyFunction() !!! \n"); |
| std::cerr << std::flush ; // Flush anything in the data buffer |
| if ( VF_rtn ) |
| { |
| DPT0( "VVzzz12: ", VV_VD, "llvm::verifyFunction returned TRUE -- " |
| "meaning function is corrupt ???\n" ); |
| std::string myText = myBuffer.str(); |
| DPT2( "VVzzz14: ", VV_VD, "%ld bytes of text:\n %s\n", |
| myText.length(), myText.data() ); |
| } |
| else |
| { |
| DPT0( "VVzzz16: ", VV_VD, "llvm::verifyFunction returned FALSE -- " |
| "meaning function verifies OK !\n" ); |
| } |
| } |
| #endif // NExprDbgLvl >= VV_BD |
| |
| std::cerr.rdbuf(old); // Restore stderr |
| |
| // ********************************************************************* |
| // Perform Optimizations |
| // ********************************************************************* |
| |
| // |
| // Change the following "if (1)" to "if (0)" when debugging future |
| // changes to Native Expressions and you would like the generated |
| // native expression to be more easily understood code ... OR if you |
| // suspect that these LLVM optimizations might be resulting in |
| // incorrect generated code. |
| // |
| if ( 1 ) |
| { |
| FunctionPassManager ExprFPM(TheModule); |
| |
| // Set up the optimizer pipeline. Start with registering info about |
| // how the target lays out data structures. |
| ExprFPM.add(new DataLayout(*TheExecutionEngine->getDataLayout())); |
| // Provide basic AliasAnalysis support for GVN. |
| ExprFPM.add(createBasicAliasAnalysisPass()); |
| // Do simple "peephole" optimizations and bit-twiddling optzns. |
| ExprFPM.add(createInstructionCombiningPass()); |
| // Reassociate expressions. |
| ExprFPM.add(createReassociatePass()); |
| // Eliminate Common SubExpressions. |
| ExprFPM.add(createGVNPass()); |
| // Simplify the control flow graph (deleting unreachable blocks, etc). |
| ExprFPM.add(createCFGSimplificationPass()); |
| |
| ExprFPM.doInitialization(); |
| |
| // Set the global so the code gen can use this. |
| // static FunctionPassManager * TheFPM = &ExprFPM; |
| |
| // Optimize the function. |
| ExprFPM.run(*ExpFn); |
| } |
| |
| #if NExprDbgLvl >= VV_BD |
| if ( NExprDbgLvl_ >= VV_BD ) |
| { |
| // ******************************************************************** |
| // Dump the Intermediate Representation (IR) |
| // ******************************************************************** |
| |
| NExLog("\nIntermediate Representation (IR) dump:"); |
| NExLog("\n======================================\n\n"); |
| |
| // Dump the module/function |
| |
| // If CQD set to dump NE debug stuff to a file, then: |
| if ( NExDbgInfoPtr_->getNExLogPath() && |
| NExDbgInfoPtr_->getNExLogPath()[0] != '\0' ) |
| { |
| std::string myErrorInfoStr; |
| raw_fd_ostream *myOuts = new raw_fd_ostream( |
| (const char *)NExDbgInfoPtr_->getNExLogPath(), |
| myErrorInfoStr, |
| (unsigned) llvm::raw_fd_ostream::F_Append |
| ); |
| |
| TheModule->print( *myOuts, (llvm::AssemblyAnnotationWriter*)NULL ); |
| } |
| else // Dump it to stdout |
| TheModule->print( outs(), (llvm::AssemblyAnnotationWriter*)NULL ); |
| |
| } |
| #endif // NExprDbgLvl >= VV_BD |
| |
| // ********************************************************************* |
| // jit -- and copy binary into buffer |
| // ********************************************************************* |
| |
| |
| // JIT the function, returning a function pointer. |
| |
| MachineCodeInfo myMachineCodeInfo; |
| |
| TheExecutionEngine->runJITOnFunction( ExpFn, &myMachineCodeInfo ); |
| |
| void *FPtr = myMachineCodeInfo.address(); |
| size_t funcBufLen = myMachineCodeInfo.size() ; |
| |
| // |
| // DON'T NEED THIS IN PRODUCT, but something like this might be |
| // useful in debugging. |
| // |
| #if 0 |
| #define MAX_EXEC_BUF_LEN 65536 /* Arbitrary maximum length - pick your own */ |
| if ( funcBufLen >= MAX_EXEC_BUF_LEN ) |
| { |
| printf( "MACHINE CODE LENGTH BIGGER THAN 65536 -- consequently questionable\n"); |
| delete Bldr; |
| //delete TheModule; |
| delete TheExecutionEngine; |
| |
| // |
| // Restore signal handlers to what they were on entry. ALSO, if this is |
| // the first time LLVM was called, save the LLVM handlers! |
| // |
| for (Int32 ii = 0; ii < NumSaveSigs ; ii++ ) |
| { |
| Int32 ret = sigaction( SaveSigs[ii], &(SavedSigInfo[ii].SigAct), |
| (LLVMhandlersSaved == FALSE) ? |
| &(SavedLLVMhandlers[ii].SigAct) : (struct sigaction *)NULL); |
| assert( ret == 0 ); |
| } |
| LLVMhandlersSaved = TRUE ; |
| pthread_mutex_unlock( &Our_LLVM_mutex ); // Other threads could use LLVM now |
| |
| |
| printf("EXITING FROM layoutNativeCode() - funcBufLen >= 65536 \n"); |
| std::cout << std::flush ; // Flush anything in the data buffer |
| expr_->setEvalPtr( (ex_expr::evalPtrType)( (CollIndex) 0 ) );//Ensure NULL! |
| return; |
| } |
| #endif |
| |
| #if NExprDbgLvl >= VV_BD |
| if ( ( NExprDbgLvl_ >= VV_BD ) && |
| ( |
| ( ( NExDbgInfoPtr_->getNExStmtSrc() != NULL ) && |
| ( NExDbgInfoPtr_->getNExStmtSrc()[0] != '\0' ) ) |
| ) |
| ) |
| { |
| // ******************************************************************** |
| // Dump the assembly code |
| // ******************************************************************** |
| |
| char insnLine[256]; |
| char insnLine2[256]; |
| |
| char * NExLogPth = NULL ; |
| |
| if ( NExDbgInfoPtr_ && NExDbgInfoPtr_ > (NExDbgInfo *)4096 ) // May be offset |
| NExLogPth = NExDbgInfoPtr_->getNExLogPath() ; |
| |
| sprintf( insnLine, "\nNative Expr (Length: %ld bytes)", funcBufLen ); |
| NExLog( insnLine ); |
| NExLog( "\n======================================\n" ); |
| |
| if ( funcBufLen <= 0 ) |
| { |
| NExLog( "MACHINE CODE LENGTH <= 0\n"); |
| NExLog("EXITING FROM layoutNativeCode() - funcBufLen <= 0 !!\n"); |
| std::cout << std::flush ; // Flush anything in the data buffer |
| delete Bldr; |
| //delete TheModule; |
| delete TheExecutionEngine; |
| |
| // |
| // Restore signal handlers to what they were on entry. ALSO, if this is |
| // the first time LLVM was called, save the LLVM handlers! |
| // |
| for (Int32 ii = 0; ii < NumSaveSigs ; ii++ ) |
| { |
| Int32 ret = sigaction( SaveSigs[ii], &(SavedSigInfo[ii].SigAct), |
| (LLVMhandlersSaved == FALSE) ? |
| &(SavedLLVMhandlers[ii].SigAct) : (struct sigaction *)NULL); |
| assert( ret == 0 ); |
| } |
| LLVMhandlersSaved = TRUE ; |
| pthread_mutex_unlock( &Our_LLVM_mutex ); // Other threads could use LLVM now |
| |
| expr_->setEvalPtr( (ex_expr::evalPtrType)( (CollIndex) 0 ) );//Ensure NULL! |
| return; |
| } |
| |
| ud_t ud_obj; |
| ud_init(&ud_obj); |
| ud_set_input_buffer(&ud_obj, (uint8_t*)FPtr, (size_t) funcBufLen); |
| ud_set_mode(&ud_obj, 64); |
| ud_set_syntax(&ud_obj, UD_SYN_ATT); |
| ud_set_vendor(&ud_obj, UD_VENDOR_INTEL); |
| |
| while (ud_disassemble(&ud_obj)) |
| { |
| if ( 0xcd == * ud_insn_ptr(&ud_obj) ) break; // end of data bug workaround |
| |
| // Find length of next assembler language instruction |
| sprintf( insnLine, "%s", ud_insn_asm(&ud_obj) ) ; |
| Int32 insnLen = str_len( insnLine ); |
| |
| if ( insnLen >= 26 ) |
| { |
| str_pad(&insnLine[insnLen], 1, ' '); |
| insnLine[insnLen+1] ='\0' ; |
| } |
| else |
| { |
| str_pad(&insnLine[insnLen],(26-insnLen+1), ' '); |
| insnLine[27] ='\0' ; |
| } |
| insnLen = str_len( insnLine ); //Increase insnLen for added spaces |
| |
| Int32 ooo = 0; |
| for (Int32 jjj = 0; jjj < insnLen; jjj++ , ooo++) |
| { |
| // If output will be going to stdout (via printf) |
| // then we must double any '%' chars in the Assembler Language |
| // |
| if ( ( ! NExLogPth || *NExLogPth == '\0' ) && |
| (insnLine[jjj] == '%') ) |
| { |
| insnLine2[ooo] = '%'; |
| ooo++; |
| } |
| insnLine2[ooo] = insnLine[jjj] ; |
| } |
| insnLine2[ooo] = '\0'; // Ensure termination |
| sprintf( NExBuf, "\t%s%s\n", insnLine2, ud_insn_hex(&ud_obj) ); |
| NExLog( NExBuf ); |
| } |
| } |
| #endif // NExprDbgLvl >= VV_BD |
| // Get entry point into function and add code into constants array |
| ex_expr::evalPtrType entry = (ex_expr::evalPtrType)FPtr; |
| CollIndex* offPtr = addConstant((void*)entry, funcBufLen, 8); |
| |
| #if NExprDbgLvl >= VV_I0 |
| if ( NExprDbgLvl_ >= VV_I0 ) |
| { |
| struct rusage endTime; |
| (void) getrusage( RUSAGE_THREAD, &endTime ); |
| |
| Int64 totalTime = ( endTime.ru_utime.tv_sec - begTime.ru_utime.tv_sec ) * 1000000 + |
| ( endTime.ru_utime.tv_usec - begTime.ru_utime.tv_usec ) ; |
| |
| DPT2( "VVzzz99: ", VV_I0, "NORMAL EXIT from layoutNativeCode(): " |
| "%ld microseconds to translate %d PCODE instructions\n", |
| totalTime, PCI_count ); |
| } |
| #endif // NExprDbgLvl >= VV_I0 |
| |
| #if 1 /* Use #if 0 to generate/compile, but NOT actually execute generated code */ |
| // Store offset into evalPtr_ |
| expr_->setEvalPtr((ex_expr::evalPtrType)((long)*offPtr)); |
| |
| // Mark this expression appropriately so that the native function gets called |
| expr_->setPCodeMoveFastpath(TRUE); |
| expr_->setPCodeNative(TRUE); |
| #endif |
| |
| TheExecutionEngine->freeMachineCodeForFunction( ExpFn ); |
| delete Bldr; |
| //delete TheModule; |
| delete TheExecutionEngine; |
| |
| // |
| // Restore signal handlers to what they were on entry. ALSO, if this is |
| // the first time LLVM was called, save the LLVM handlers! |
| // |
| for (Int32 ii = 0; ii < NumSaveSigs ; ii++ ) |
| { |
| Int32 ret = sigaction( SaveSigs[ii], &(SavedSigInfo[ii].SigAct), |
| (LLVMhandlersSaved == FALSE) ? |
| &(SavedLLVMhandlers[ii].SigAct) : (struct sigaction *)NULL); |
| assert( ret == 0 ); |
| } |
| LLVMhandlersSaved = TRUE ; |
| pthread_mutex_unlock( &Our_LLVM_mutex ); // Other threads could use LLVM now |
| return ; |
| } |
| |
| void PCodeCfg::layoutNativeCode(Space* showplanSpace) |
| { |
| if (expr_->getPCodeNative()) |
| { |
| NABoolean firstTimeSeen = TRUE; |
| char line[256]; |
| char insnLine[256]; |
| Int32 i; |
| void *FPtr = expr_->getConstantsArea() + expr_->getEvalPtrOffset(); |
| Long nativeCodeLen = expr_->getConstsLength() - expr_->getEvalPtrOffset(); |
| |
| // First print out a header for the native expr dump |
| sprintf( line, "Native Expr (Length: %ld bytes)", nativeCodeLen ); |
| showplanSpace->allocateAndCopyToAlignedSpace(line, str_len(line), |
| sizeof(short)); |
| |
| ud_t ud_obj; |
| ud_init(&ud_obj); |
| ud_set_input_buffer(&ud_obj, (uint8_t*)(FPtr), (size_t) nativeCodeLen); |
| ud_set_mode(&ud_obj, 64); |
| ud_set_syntax(&ud_obj, UD_SYN_ATT); |
| ud_set_vendor(&ud_obj, UD_VENDOR_INTEL); |
| |
| while (ud_disassemble(&ud_obj)) |
| { |
| if ( 0xcd == * ud_insn_ptr(&ud_obj) ) break; // end of data bug workaround |
| |
| // Find length of next assembler language instruction |
| sprintf( insnLine, "%s", ud_insn_asm(&ud_obj) ) ; |
| Int32 insnLen = str_len( insnLine ); |
| |
| if ( insnLen >= 26 ) |
| { |
| str_pad(&insnLine[insnLen], 1, ' '); |
| insnLine[insnLen+1] ='\0' ; |
| } |
| else |
| { |
| str_pad(&insnLine[insnLen],(26-insnLen+1), ' '); |
| insnLine[27] ='\0' ; |
| } |
| |
| sprintf( line, "\t%s%s", insnLine, ud_insn_hex(&ud_obj) ); |
| showplanSpace->allocateAndCopyToAlignedSpace(line, str_len(line), sizeof(short)); |
| } |
| system(line); |
| |
| // Add a newline to start the next expression off cleanly. |
| showplanSpace->allocateAndCopyToAlignedSpace("\n", 1, sizeof(short)); |
| } |
| |
| } |
| |
| #endif /* NA_LINUX_LLVMJIT */ |
| |
| #ifdef NA_LINUX_LIBJIT |
| |
| void PCodeCfg::layoutNativeCode(Space* showplanSpace = NULL) |
| { |
| NABoolean debug = FALSE; |
| NABoolean lowerOptLevel = FALSE; // Used to reduce jit opt level. |
| |
| if (getenv("NATIVE_EXPR_DEBUG")) |
| debug = TRUE; |
| |
| PCodeOperand *src1, *src2, *res; |
| |
| jit_value_t resJitVal, src1JitVal, src2JitVal; |
| jit_value_t tRes, tSrc1, tSrc2, loopIndex; |
| jit_value_t eJitVal; |
| jit_label_t* jitLabel = NULL; |
| jit_label_t errorJitLabel = jit_label_undefined; |
| jit_type_t type; |
| |
| jit_value_t padJitVal; |
| |
| Int32 opc; |
| CollIndex i, j, blockIndex; |
| |
| Int32 skipInst = 0; |
| |
| PCodeBinary* pCode = expr_->getPCodeBinary(); |
| |
| // First see if this graph can be compiled natively |
| if (!canGenerateNativeExpr()) |
| return; |
| |
| // First compute the dominator tree |
| computeDomTree(); |
| |
| // Create context to hold the JIT's primary state |
| jit_context_t context = jit_context_create(); |
| |
| // Lock the context while we build and compile the function. This is only |
| // really necessary in a multithreaded environment. |
| jit_context_build_start(context); |
| |
| // Generate code for getting tupp pointers |
| // |
| // 1. Get atp pointer (p) passed in |
| // 2. Add bytes to get to tuple we care about |
| // off = &(tempAtp->getTupp(atpIndex)) - (tempAtp) |
| // temp1 = param[atp] + off; |
| // 3. Dereference pointer to get tupp_descriptor pointer |
| // temp2 = load(temp1); |
| // 4. Add bytes to get to dataTuple |
| // off = &(tempTuppDesc.getTupleAddress() |
| |
| atp_struct tempAtp; |
| tupp tempTupp; |
| tupp_descriptor tempTuppDesc; |
| |
| /* |
| ex_cri_desc criDesc; |
| tempAtp.setCriDesc(&criDesc); |
| */ |
| |
| // Build the function signature. |
| jit_type_t params[4]; |
| params[0] = jit_type_void_ptr; // Int32* pCode32 |
| params[1] = jit_type_void_ptr; // atp_struct* atp2 |
| params[2] = jit_type_void_ptr; // atp_struct* atp2 |
| params[3] = jit_type_void_ptr; // Int32* constants |
| |
| jit_type_t signature = |
| jit_type_create_signature(jit_abi_cdecl, jit_type_int, params, 4, 1); |
| |
| // Create function |
| jit_function_t f = jit_function_create(context, signature); |
| |
| // Create commonly referenced constants |
| oneJitVal_ = jit_value_create_nint_constant(f, jit_type_int, 1); |
| zeroJitVal_ = jit_value_create_nint_constant(f, jit_type_int, 0); |
| neg1JitVal_ = jit_value_create_nint_constant(f, jit_type_int, -1); |
| jit_value_t zeroJitVal16=jit_value_create_nint_constant(f, jit_type_short, 0); |
| jit_value_t neg1JitVal16=jit_value_create_nint_constant(f, jit_type_short,-1); |
| padJitVal = jit_value_create_nint_constant(f, jit_type_ubyte, ' '); |
| jit_value_t shiftRVal = jit_value_create_nint_constant(f, jit_type_int, 31); |
| okJitVal_ = jit_value_create_nint_constant(f, jit_type_int,ex_expr::EXPR_OK); |
| tJitVal_ = jit_value_create_nint_constant(f, jit_type_int,ex_expr::EXPR_TRUE); |
| fJitVal_ = jit_value_create_nint_constant(f,jit_type_int,ex_expr::EXPR_FALSE); |
| eJitVal = jit_value_create_nint_constant(f,jit_type_int,ex_expr::EXPR_ERROR); |
| |
| // Used for bignum related ops when manipulating sign bit. |
| jit_value_t jitVal16 = jit_value_create_nint_constant(f, jit_type_uint, 16); |
| jit_value_t jitValMask16 = |
| jit_value_create_nint_constant(f, jit_type_ushort, 0x8000); |
| jit_value_t jitValMask32 = |
| jit_value_create_nint_constant(f, jit_type_ushort, 0x80000000); |
| jit_value_t jitValNotMask16 = |
| jit_value_create_nint_constant(f, jit_type_ushort, 0x7fff); |
| jit_value_t jitValNotMask32 = |
| jit_value_create_nint_constant(f, jit_type_ushort, 0x7fffffff); |
| |
| // Allocate pointers to global defs available at runtime. Note, if they are |
| // not referenced by the pcode graph, these loads will be deleted by the jit. |
| jit_value_t globTableJitVal = jit_value_get_param(f, 0); |
| jit_value_t nullTable = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_NULL_TABLE, |
| jit_type_void_ptr); |
| |
| hashTableJitVal_ = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_RANDOM_HASH_VALS_TABLE, |
| jit_type_void_ptr); |
| |
| jit_value_t compareWithPadJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_COMPARE_WITH_PAD_FUNC, |
| jit_type_void_ptr); |
| |
| jit_value_t strcmpJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_STRCMP_FUNC, jit_type_void_ptr); |
| |
| jit_value_t strcpyJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_STRCPY_FUNC, jit_type_void_ptr); |
| |
| jit_value_t dblLeJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_DBL_LE_CMP_FUNC, jit_type_void_ptr); |
| jit_value_t dblGeJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_DBL_GE_CMP_FUNC, jit_type_void_ptr); |
| jit_value_t dblLtJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_DBL_LT_CMP_FUNC, jit_type_void_ptr); |
| jit_value_t dblGtJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_DBL_GT_CMP_FUNC, jit_type_void_ptr); |
| jit_value_t dblEqJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_DBL_EQ_CMP_FUNC, jit_type_void_ptr); |
| jit_value_t dblNeJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_DBL_NE_CMP_FUNC, jit_type_void_ptr); |
| jit_value_t reportErrJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_REPORT_ERR_FUNC, jit_type_void_ptr); |
| jit_value_t bigSubJitVal = jit_insn_load_relative(f, globTableJitVal, |
| JIT_GLOB_BIG_SUB_FUNC, jit_type_void_ptr); |
| |
| |
| jit_type_t compareParams[5] = {jit_type_void_ptr, jit_type_int, |
| jit_type_void_ptr, jit_type_int, |
| jit_type_ubyte}; |
| jit_type_t strcmpParams[5] = {jit_type_void_ptr, jit_type_void_ptr, |
| jit_type_uint}; |
| jit_type_t strcpyParams[5] = {jit_type_void_ptr, jit_type_void_ptr, |
| jit_type_uint}; |
| jit_type_t dblParams[2] = {jit_type_float64, jit_type_float64}; |
| jit_type_t reportErrParams[2] = {jit_type_void_ptr, jit_type_void_ptr}; |
| jit_type_t bigParams[4] = {jit_type_void_ptr, jit_type_void_ptr, |
| jit_type_void_ptr, jit_type_uint}; |
| |
| |
| jit_type_t compareSig = jit_type_create_signature (jit_abi_cdecl, |
| jit_type_int, compareParams, 5, 1); |
| |
| jit_type_t strcmpSig = jit_type_create_signature (jit_abi_cdecl, |
| jit_type_int, strcmpParams, 3, 1); |
| jit_type_t strcpySig = jit_type_create_signature (jit_abi_cdecl, |
| jit_type_int, strcpyParams, 3, 1); |
| jit_type_t dblSig = jit_type_create_signature (jit_abi_cdecl, |
| jit_type_int, dblParams, 2, 1); |
| jit_type_t reportErrSig = jit_type_create_signature (jit_abi_cdecl, |
| jit_type_int, reportErrParams, 2, 1); |
| jit_type_t bigSig = jit_type_create_signature (jit_abi_cdecl, |
| jit_type_int, bigParams, 4, 1); |
| |
| |
| |
| // Allocate incoming parameters |
| jitParams_ = (jit_value_t*) new(heap_) jit_value_t[4 + pCode[0]]; |
| for (i=0, j=1; i < (CollIndex)pCode[0]; i++, j+=2) |
| { |
| Int32 off1, off2; |
| |
| // First get the atp we care about |
| jit_value_t t1 = jit_value_get_param(f, 1 + pCode[j]); |
| |
| // Get the tupp descriptor pointer we care about |
| off1 = |
| (char*)(&(tempAtp.getTuppForNativeExpr(pCode[j+1]))) - (char*)(&tempAtp); |
| jit_value_t t2 = jit_insn_load_relative(f, t1, off1, jit_type_void_ptr); |
| |
| #if NULL_TUPLE_PTRS |
| jit_label_t storeNullLabel = jit_label_undefined; |
| jit_value_t res = jit_value_create(f, jit_type_void_ptr); |
| |
| jit_value_t t4 = jit_insn_eq(f, t2, zeroJitVal_); |
| jit_insn_branch_if(f, t4, &storeNullLabel); |
| #endif |
| |
| // Lastly, get the tuple pointer |
| off2 = 12; // (&(tempTuppDesc.getTupleAddress())) - (&tempTuppDesc); |
| jit_value_t t3 = jit_insn_load_relative(f, t2, off2, jit_type_void_ptr); |
| |
| #if NULL_TUPLE_PTRS |
| // Set tuple pointers to nullData if they are NULL. Only need to do this for |
| // 2.4.2 and below. |
| jit_insn_store(f, res, t3); |
| |
| jit_label_t storeLabel = jit_label_undefined; |
| |
| t4 = jit_insn_eq(f, t3, zeroJitVal_); |
| jit_insn_branch_if_not(f, t4, &storeLabel); |
| |
| jit_insn_label(f, &storeNullLabel); |
| jit_insn_store(f, res, nullTable); |
| |
| jit_insn_label(f, &storeLabel); |
| |
| // Make t3 the result so that we properly store (internally) what the tuple |
| // pointer is. |
| t3 = res; |
| #endif |
| |
| jitParams_[4+i] = t3; |
| } |
| |
| // |
| // Allocate incoming constant pointer (needed for strings and floats). The |
| // constantsArea_ pointer is 88 bytes from the object (note, we hardcode this |
| // since access to the member variables are protected, and therefore not |
| // accessible for use in calculating this automatically). The 88 byte offset |
| // comes from "20" being the offset to the "eyeCatcher_" field, plus "56" to |
| // the constants area; |
| // |
| // Do the same for the temps array pointer. This array is used to store to |
| // those temps which usually don't fit within a native container - e.g. |
| // strings and bignums. The temps array is just above the constants area in |
| // the expr - i.e. at "64" bytes from the eyeCatcher_. |
| // |
| jit_value_t exprJitVal = jit_value_get_param(f,3); |
| jitParams_[1] = jit_insn_load_relative(f, exprJitVal, 88, jit_type_void_ptr); |
| jitParams_[2] = jit_insn_load_relative(f, exprJitVal, 96, jit_type_void_ptr); |
| |
| // Create temp values used for strings (or data in general) |
| tRes = jit_value_create(f, jit_type_void_ptr); // ptr to walk string |
| tSrc1 = jit_value_create(f, jit_type_void_ptr); // ptr to walk string |
| tSrc2 = jit_value_create(f, jit_type_void_ptr); // ptr to walk string |
| loopIndex = jit_value_create(f, jit_type_int); // loop index for strcmp |
| |
| // Allocate and initialize opData array for use with CLAUSE_EVAL instructions |
| PCodeOperand* opData[(3*ex_clause::MAX_OPERANDS)]; |
| PCodeOperand** opDataNulls = &(opData[0]); |
| PCodeOperand** opDataVals = &(opData[2*ex_clause::MAX_OPERANDS]); |
| str_pad((char*)opData, (3*ex_clause::MAX_OPERANDS)*sizeof(PCodeOperand*), 0); |
| |
| // Create the list of basic blocks in physical layout order |
| BLOCKLIST physBlockList(heap_); |
| |
| createPhysList(physBlockList); |
| |
| // Loop through each block, generating instructions on a per block basis. We |
| // stop immediately if a failure was seen during code gen. |
| |
| for (blockIndex=0; |
| (blockIndex < physBlockList.entries()) && !getJitFailureSeen(); |
| blockIndex++) |
| { |
| PCodeBlock* block = physBlockList[blockIndex]; |
| |
| // Lay out the label for this block. |
| jit_insn_label(f, block->getJitLabel()); |
| |
| FOREACH_INST_IN_BLOCK(block, inst) { |
| |
| // If a failure occurred, stop translation immediately. |
| if (getJitFailureSeen()) |
| break; |
| |
| // Sometimes native code is generated for multiple pcode instructions in |
| // one pass, and so "skipped" instructions don't need to be processed. |
| if (skipInst > 0) { |
| skipInst--; |
| continue; |
| } |
| |
| opc = inst->getOpcode(); |
| switch (opc) { |
| |
| case PCIT::MOVE_MATTR5_MATTR5: |
| { |
| jit_type_t vcType; |
| jit_value_t vcLenJitVal; |
| |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| if (src1->getVcIndicatorLen() == 2) { |
| vcType = jit_type_ushort; |
| vcLenJitVal = jit_value_create_nint_constant(f, jit_type_int, 2); |
| } |
| else { |
| vcType = jit_type_uint; |
| vcLenJitVal = jit_value_create_nint_constant(f, jit_type_int, 4); |
| } |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| |
| jit_insn_store(f, tRes, resJitVal); |
| jit_insn_store(f, tSrc1, src1JitVal); |
| |
| jit_value_t srcLen = jit_insn_load_relative(f, src1JitVal, 0, vcType); |
| srcLen = jit_insn_add(f, srcLen, vcLenJitVal); |
| |
| genUnalignedMemcpy(f, tRes, tSrc1, srcLen); |
| |
| #if 0 |
| jit_value_t tgtLen = jit_insn_load_relative(f, resJitVal, 0, vcType); |
| |
| // Just store in length for now. |
| jit_insn_store_relative(f, resJitVal, 0, srcLen); |
| |
| src1JitVal = |
| jit_insn_add_relative(f, src1JitVal, src1->getVcIndicatorLen()); |
| resJitVal = |
| jit_insn_add_relative(f, resJitVal, src1->getVcIndicatorLen()); |
| |
| jit_insn_store(f, tSrc1, src1JitVal); |
| jit_insn_store(f, tSrc2, src2JitVal); |
| |
| // Now copy string |
| jit_insn_memcpy(f, resJitVal, src1JitVal, srcLen); |
| #endif |
| |
| break; |
| } |
| |
| case PCIT::BRANCH: |
| { |
| jit_insn_branch(f, block->getTargetBlock()->getJitLabel()); |
| break; |
| } |
| |
| |
| case PCIT::BRANCH_OR: |
| case PCIT::BRANCH_AND: |
| case PCIT::BRANCH_OR_CNT: |
| case PCIT::BRANCH_AND_CNT: |
| { |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| jit_value_t takenJitVal = |
| ((opc == PCIT::BRANCH_OR) || (opc == PCIT::BRANCH_OR_CNT)) |
| ? oneJitVal_ : zeroJitVal_; |
| |
| jitLabel = block->getTargetBlock()->getJitLabel(); |
| |
| src1JitVal = src1->getJitValue(this, f, jit_type_int, block); |
| |
| if (res->isVar() || block->isOperandLiveInSuccs(res)) |
| res->storeJitValue(this, f, jit_type_int, src1JitVal, block, NULL); |
| |
| resJitVal = jit_insn_eq(f, src1JitVal, takenJitVal); |
| jit_insn_branch_if(f, resJitVal, jitLabel); |
| |
| break; |
| } |
| |
| case PCIT::NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S: |
| { |
| jit_label_t src1LabelNull = jit_label_undefined; |
| jit_label_t ret1Label = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| |
| jitLabel = block->getTargetBlock()->getJitLabel(); |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| res = inst->getWOps()[0]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| jit_insn_branch_if(f, src1JitVal, &src1LabelNull); |
| jit_insn_branch_if(f, src2JitVal, &ret1Label); |
| |
| // Both are not null - store 0 and take target branch |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| jit_insn_branch(f, jitLabel); |
| |
| // Src1 is null - what about src2? |
| jit_insn_label(f, &src1LabelNull); |
| jit_insn_branch_if(f, src2JitVal, &ret1Label); |
| |
| // Src2 is not null, so return 0 |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| |
| // Return 1 |
| jit_insn_label(f, &ret1Label); |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| |
| // End label to jump to |
| jit_insn_label(f, &endLabel); |
| |
| break; |
| } |
| |
| case PCIT::NNB_MATTR3_IBIN32S: |
| { |
| src1 = inst->getROps()[0]; |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| |
| jitLabel = block->getTargetBlock()->getJitLabel(); |
| jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| |
| break; |
| } |
| |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S: |
| { |
| jit_value_t orRes; |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| res = inst->getWOps()[0]; |
| |
| NABoolean forComp = (opc == |
| PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S); |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| orRes = jit_insn_or(f, src1JitVal, src2JitVal); |
| |
| jitLabel = block->getTargetBlock()->getJitLabel(); |
| |
| if (res->isVar() || block->isOperandLiveInSuccs(res)) { |
| res->storeNullJitValueAndBranch(this, f, orRes, jitLabel, |
| forComp, block); |
| } |
| else { |
| jit_insn_branch_if_not(f, orRes, jitLabel); |
| } |
| |
| break; |
| } |
| |
| case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S: |
| { |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| NABoolean forComp = |
| (opc == PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S); |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| jitLabel = block->getTargetBlock()->getJitLabel(); |
| |
| if (res->isVar() || block->isOperandLiveInSuccs(res)) { |
| res->storeNullJitValueAndBranch(this, f, src1JitVal, jitLabel, |
| forComp, block); |
| } |
| else { |
| jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| } |
| |
| break; |
| } |
| |
| case PCIT::FILL_MEM_BYTES_VARIABLE: |
| case PCIT::FILL_MEM_BYTES: |
| { |
| #ifdef NO_FILL_MEM_BYTES |
| break; |
| #endif |
| Int32 fillVal, fillLen; |
| |
| res = inst->getWOps()[0]; |
| |
| // Also, no need to zero out temporary operands, since we just care |
| // about their values being appropriately nulled out. |
| if (res->isTemp()) |
| break; |
| |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| |
| if (opc == PCIT::FILL_MEM_BYTES_VARIABLE) |
| { |
| jit_value_t lenJitVal; |
| |
| Int32 vcLen = res->getVcIndicatorLen(); |
| jit_type_t vcType = (vcLen == 2) ? jit_type_ushort : jit_type_uint; |
| |
| lenJitVal = jit_value_create_nint_constant(f, vcType,inst->code[6]); |
| |
| // Write out vc length first |
| jit_insn_store_relative(f, resJitVal, 0, lenJitVal); |
| |
| // Move pointer up |
| resJitVal = jit_insn_add_relative(f, resJitVal, vcLen); |
| |
| // Reduce fill length to no longer include vc length indicator |
| fillLen = inst->code[6] - vcLen; |
| fillVal = inst->code[7]; |
| } |
| else { |
| fillLen = inst->code[3]; |
| fillVal = inst->code[4]; |
| } |
| |
| // FIXME: If varchar, we currently set the vc length to the max length |
| // of the varchar, but does that make sense if the value is NULL? |
| // This only gets called when the the varchar is NULL, and so it's |
| // length will always be zero, so why write it out?. |
| |
| genUnalignedMemset(f, resJitVal, fillVal, fillLen); |
| |
| break; |
| } |
| |
| case PCIT::COMP_MBIN32S_MASCII_MASCII_IBIN32S_IBIN32S_IBIN32S: |
| case PCIT::COMP_MBIN32S_MATTR5_MATTR5_IBIN32S: |
| { |
| jit_value_t len1, len2; |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| // Need to get pointer to operands |
| src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, block); |
| src2JitVal = src2->getJitValue(this, f, jit_type_void_ptr, block); |
| |
| // Setup for varchar and return length (if we're varchar) |
| if (src1->isVarchar()) |
| len1 = genStringSetup(f, &src1JitVal, src1); |
| else |
| len1= jit_value_create_nint_constant(f,jit_type_int,src1->getLen()); |
| |
| if (src2->isVarchar()) |
| len2 = genStringSetup(f, &src2JitVal, src2); |
| else |
| len2= jit_value_create_nint_constant(f,jit_type_int,src2->getLen()); |
| |
| |
| // Set up arguments and make indirect call to compare routine. |
| jit_value_t args[5] = {src1JitVal, len1, src2JitVal, len2, padJitVal}; |
| resJitVal = jit_insn_call_indirect(f, compareWithPadJitVal, |
| compareSig, args, 5, 0); |
| |
| Int32 subOpc = (opc == PCIT::COMP_MBIN32S_MATTR5_MATTR5_IBIN32S) |
| ? inst->code[13] : inst->code[9]; |
| |
| // Generate code for the appropriate compare operation. |
| switch (subOpc) { |
| case ITM_EQUAL: |
| resJitVal = jit_insn_eq(f, resJitVal, zeroJitVal_); |
| break; |
| case ITM_NOT_EQUAL: |
| resJitVal = jit_insn_ne(f, resJitVal, zeroJitVal_); |
| break; |
| case ITM_LESS: |
| resJitVal = jit_insn_lt(f, resJitVal, zeroJitVal_); |
| break; |
| case ITM_LESS_EQ: |
| resJitVal = jit_insn_le(f, resJitVal, zeroJitVal_); |
| break; |
| case ITM_GREATER: |
| resJitVal = jit_insn_gt(f, resJitVal, zeroJitVal_); |
| break; |
| case ITM_GREATER_EQ: |
| resJitVal = jit_insn_ge(f, resJitVal, zeroJitVal_); |
| break; |
| } |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::LE_MBIN32S_MFLT64_MFLT64: |
| case PCIT::GE_MBIN32S_MFLT64_MFLT64: |
| case PCIT::LT_MBIN32S_MFLT64_MFLT64: |
| case PCIT::GT_MBIN32S_MFLT64_MFLT64: |
| case PCIT::EQ_MBIN32S_MFLT64_MFLT64: |
| case PCIT::NE_MBIN32S_MFLT64_MFLT64: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| // Need to get pointer to operands |
| src1JitVal = src1->getJitValue(this, f, jit_type_float64, block); |
| src2JitVal = src2->getJitValue(this, f, jit_type_float64, block); |
| |
| // Set up arguments and make indirect call to compare routine. |
| jit_value_t args[2] = {src1JitVal, src2JitVal}; |
| |
| switch (opc) { |
| case PCIT::LE_MBIN32S_MFLT64_MFLT64: |
| resJitVal = jit_insn_call_indirect(f,dblLeJitVal,dblSig,args,2,0); |
| break; |
| case PCIT::GE_MBIN32S_MFLT64_MFLT64: |
| resJitVal = jit_insn_call_indirect(f,dblGeJitVal,dblSig,args,2,0); |
| break; |
| case PCIT::LT_MBIN32S_MFLT64_MFLT64: |
| resJitVal = jit_insn_call_indirect(f,dblLtJitVal,dblSig,args,2,0); |
| break; |
| case PCIT::GT_MBIN32S_MFLT64_MFLT64: |
| resJitVal = jit_insn_call_indirect(f,dblGtJitVal,dblSig,args,2,0); |
| break; |
| case PCIT::EQ_MBIN32S_MFLT64_MFLT64: |
| resJitVal = jit_insn_call_indirect(f,dblEqJitVal,dblSig,args,2,0); |
| break; |
| case PCIT::NE_MBIN32S_MFLT64_MFLT64: |
| resJitVal = jit_insn_call_indirect(f,dblNeJitVal,dblSig,args,2,0); |
| break; |
| } |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::COMP_MBIN32S_MBIGS_MBIGS_IBIN32S_IBIN32S: |
| { |
| jit_label_t loopLabel = jit_label_undefined; |
| jit_label_t falseLabel = jit_label_undefined; |
| jit_label_t trueLabel = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| jit_label_t negLabel = jit_label_undefined; |
| jit_label_t resolveLabel = jit_label_undefined; |
| jit_label_t diffSignsLabel = jit_label_undefined; |
| jit_label_t loopDiffLabel = jit_label_undefined; |
| jit_label_t emitFalseLabel = jit_label_undefined; |
| jit_label_t emitTrueLabel = jit_label_undefined; |
| |
| jit_value_t t1, t2, size, cmpRes, cmpRes2, src1Sign, src2Sign; |
| |
| // Get operands |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| CollIndex len = src1->getLen(); |
| |
| jit_value_t lenJitVal = |
| jit_value_create_nint_constant(f, jit_type_int, len); |
| |
| // Declare variables as if bignum will be processed in shorts |
| jit_type_t bignumMaxType = jit_type_ushort; |
| CollIndex startPos = len - 2; |
| jit_value_t mask = jitValMask16; |
| jit_value_t decrJitVal = |
| jit_value_create_nint_constant(f, jit_type_int, 2); |
| |
| // If bignum length is a multiple of 4, why not do 4 bytes at a time? |
| // Alignment traps may occur, but they have been shown to have a |
| // minimal impact on x86. |
| |
| if ((len % 4) == 0) { |
| bignumMaxType = jit_type_uint; |
| startPos = len - 4; |
| mask = jitValMask32; |
| decrJitVal = jit_value_create_nint_constant(f, jit_type_int, 4); |
| } |
| |
| // Get pointers to the source operands. |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| // Get the short/int containing the sign bits. |
| t1 = jit_insn_load_relative(f, src1JitVal, startPos, bignumMaxType); |
| t2 = jit_insn_load_relative(f, src2JitVal, startPos, bignumMaxType); |
| |
| // Get the sign bits |
| src1Sign = jit_insn_and(f, t1, mask); |
| src2Sign = jit_insn_and(f, t2, mask); |
| |
| // If signs don't match, branch to a fast path |
| cmpRes = jit_insn_ne(f, src1Sign, src2Sign); |
| jit_insn_branch_if(f, cmpRes, &diffSignsLabel); |
| |
| // Prepare for loop |
| size = jit_value_create_nint_constant(f, jit_type_int, startPos); |
| |
| t1 = jit_insn_add(f, src1JitVal, size); |
| t2 = jit_insn_add(f, src2JitVal, size); |
| jit_insn_store(f, tSrc1, t1); |
| jit_insn_store(f, tSrc2, t2); |
| |
| // Loop header: "loop index = length" |
| jit_insn_store(f, loopIndex, lenJitVal); |
| |
| // Body: "while()" |
| jit_insn_label(f, &loopLabel); |
| |
| // Get byte in string to compare |
| t1 = jit_insn_load_relative(f, tSrc1, 0, bignumMaxType); |
| t2 = jit_insn_load_relative(f, tSrc2, 0, bignumMaxType); |
| |
| // Perform comparison(s) and branch. For eq/ne we just do one |
| // comparison. For all others we do 2 comparisons. The 2 compares |
| // are done together, since libjit otherwise spills and restores the |
| // arguments before each compare and branch! |
| |
| Int32 subOpc = inst->code[8]; |
| switch (subOpc) { |
| case ITM_EQUAL: |
| cmpRes = jit_insn_ne(f, t1, t2); |
| // Jump directly to "return false" code |
| jit_insn_branch_if(f, cmpRes, &resolveLabel); |
| break; |
| case ITM_NOT_EQUAL: |
| cmpRes = jit_insn_ne(f, t1, t2); |
| // Jump directly to "return true" code |
| jit_insn_branch_if(f, cmpRes, &resolveLabel); |
| break; |
| case ITM_LESS: |
| cmpRes = jit_insn_gt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| cmpRes2 = jit_insn_lt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| break; |
| case ITM_LESS_EQ: |
| cmpRes = jit_insn_gt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| cmpRes2 = jit_insn_lt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| break; |
| case ITM_GREATER: |
| cmpRes = jit_insn_lt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| cmpRes2 = jit_insn_gt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| break; |
| case ITM_GREATER_EQ: |
| cmpRes = jit_insn_lt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| cmpRes2 = jit_insn_gt(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| break; |
| } |
| |
| // Decrement loop index |
| t1 = jit_insn_sub(f, loopIndex, decrJitVal); |
| jit_insn_store(f, loopIndex, t1); |
| |
| // Increment string pointers |
| t1 = jit_insn_sub(f, tSrc1, decrJitVal); |
| t2 = jit_insn_sub(f, tSrc2, decrJitVal); |
| jit_insn_store(f, tSrc1, t1); |
| jit_insn_store(f, tSrc2, t2); |
| |
| // Branch back if loop index <> 0 |
| jit_insn_branch_if(f, loopIndex, &loopLabel); |
| |
| // If we reach this point, the two sources are equal to each other. |
| if (subOpc == ITM_EQUAL) |
| { |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| } |
| else if (subOpc == ITM_NOT_EQUAL) { |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| } |
| else |
| { |
| // GE or LE will return TRUE right away. |
| if ((subOpc == ITM_GREATER_EQ) || (subOpc == ITM_LESS_EQ)) { |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| } |
| |
| // False block emitted first, since we fall-through to it. |
| jit_insn_label(f, &falseLabel); |
| |
| // If sources are negative, then return the opposite. |
| jit_insn_branch_if(f, src1Sign, &emitTrueLabel); |
| |
| jit_insn_label(f, &emitFalseLabel); |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| |
| // True block |
| jit_insn_label(f, &trueLabel); |
| |
| // If sources are negative, then return the opposite. |
| jit_insn_branch_if(f, src1Sign, &emitFalseLabel); |
| |
| jit_insn_label(f, &emitTrueLabel); |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| } |
| |
| // Handle difference in signs here. Normally a difference in signs |
| // is enough to make the comparison, but because we can have both -0 |
| // and +0 (which are both equivalent), we have to make this code a |
| // little lengthy. |
| |
| jit_insn_label(f, &diffSignsLabel); |
| |
| // Loop header: "loop index = 0" |
| jit_insn_store(f, loopIndex, zeroJitVal_); |
| |
| // Body: "while()" |
| jit_insn_label(f, &loopDiffLabel); |
| |
| // Get byte in string to compare |
| t1 = jit_insn_load_elem(f, src1JitVal, loopIndex, bignumMaxType); |
| t2 = jit_insn_load_elem(f, src2JitVal, loopIndex, bignumMaxType); |
| |
| // Are the two different from each other? |
| cmpRes = jit_insn_ne(f, t1, t2); |
| jit_insn_branch_if(f, cmpRes, &resolveLabel); |
| |
| // Are the two equal to 0? |
| cmpRes = jit_insn_ne(f, t1, zeroJitVal_); |
| jit_insn_branch_if(f, cmpRes, &resolveLabel); |
| |
| // Increment loop index |
| t1 = jit_insn_add(f, loopIndex, decrJitVal); |
| jit_insn_store(f, loopIndex, t1); |
| |
| // Branch back if loop index == length |
| t1 = jit_insn_ne(f, loopIndex, lenJitVal); |
| jit_insn_branch_if(f, loopIndex, &loopDiffLabel); |
| |
| if ((subOpc == ITM_EQUAL) || (subOpc == ITM_LESS_EQ) || |
| (subOpc == ITM_GREATER_EQ)) |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| else |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| |
| jit_insn_branch(f, &endLabel); |
| |
| // We arrive here if 1) the signs are different, 2) we verified that |
| // we don't have a +0/-0 situation. In this case, EQ & NE can do a |
| // fast return. The other comparisons must check the sign directly |
| // before making a decision on what to do. |
| |
| jit_insn_label(f, &resolveLabel); |
| |
| switch (subOpc) { |
| case ITM_EQUAL: |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| break; |
| case ITM_NOT_EQUAL: |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| break; |
| |
| default: |
| { |
| jit_insn_branch_if(f, src1Sign, &negLabel); |
| if ((subOpc == ITM_GREATER) || (subOpc == ITM_GREATER_EQ)) |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| else |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| |
| jit_insn_branch(f, &endLabel); |
| |
| // Negative label |
| jit_insn_label(f, &negLabel); |
| if ((subOpc == ITM_GREATER) || (subOpc == ITM_GREATER_EQ)) |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| else |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| |
| break; |
| } |
| } |
| |
| // End label |
| jit_insn_label(f, &endLabel); |
| |
| break; |
| } |
| |
| |
| case PCIT::EQ_MBIN32S_MASCII_MASCII: |
| case PCIT::NE_MBIN32S_MASCII_MASCII: |
| case PCIT::LT_MBIN32S_MASCII_MASCII: |
| case PCIT::GT_MBIN32S_MASCII_MASCII: |
| case PCIT::LE_MBIN32S_MASCII_MASCII: |
| case PCIT::GE_MBIN32S_MASCII_MASCII: |
| { |
| jit_value_t size, b1, b2, cmpRes, cmpRes2; |
| jit_value_t temp1, temp2, temp3; |
| jit_label_t loopLabel = jit_label_undefined; |
| jit_label_t falseLabel = jit_label_undefined; |
| jit_label_t trueLabel = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| |
| NABoolean isEqOrNe = (opc == PCIT::EQ_MBIN32S_MASCII_MASCII) || |
| (opc == PCIT::NE_MBIN32S_MASCII_MASCII); |
| |
| NABoolean dumpTrueBlockFirst = TRUE; // May change later |
| |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| jit_insn_store(f, tSrc1, src1JitVal); |
| jit_insn_store(f, tSrc2, src2JitVal); |
| |
| // Loop header: "loop index = length" |
| size = jit_value_create_nint_constant(f, jit_type_int,src1->getLen()); |
| jit_insn_store(f, loopIndex, size); |
| |
| // Body: "while()" |
| jit_insn_label(f, &loopLabel); |
| |
| // Get byte in string to compare |
| b1 = jit_insn_load_relative(f, tSrc1, 0, jit_type_ubyte); |
| b2 = jit_insn_load_relative(f, tSrc2, 0, jit_type_ubyte); |
| |
| // Perform comparison(s) and branch. For eq/ne we just do one |
| // comparison. For all others we do 2 comparisons. The 2 compares |
| // are done together, since libjit otherwise spills and restores the |
| // arguments before each compare and branch! |
| |
| if (opc == PCIT::EQ_MBIN32S_MASCII_MASCII) { |
| cmpRes = jit_insn_ne(f, b1, b2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| } |
| else if (opc == PCIT::NE_MBIN32S_MASCII_MASCII) { |
| cmpRes = jit_insn_ne(f, b1, b2); |
| jit_insn_branch_if(f, cmpRes, &trueLabel); |
| dumpTrueBlockFirst = FALSE; |
| } |
| else if (opc == PCIT::LT_MBIN32S_MASCII_MASCII) { |
| cmpRes = jit_insn_gt(f, b1, b2); |
| cmpRes2 = jit_insn_lt(f, b1, b2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| dumpTrueBlockFirst = FALSE; |
| } |
| else if (opc == PCIT::GT_MBIN32S_MASCII_MASCII) { |
| cmpRes = jit_insn_lt(f, b1, b2); |
| cmpRes2 = jit_insn_gt(f, b1, b2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| dumpTrueBlockFirst = FALSE; |
| } |
| else if (opc == PCIT::LE_MBIN32S_MASCII_MASCII) { |
| cmpRes = jit_insn_gt(f, b1, b2); |
| cmpRes2 = jit_insn_lt(f, b1, b2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| } |
| else /* (opc == PCIT::GE_MBIN32S_MASCII_MASCII) */ { |
| cmpRes = jit_insn_lt(f, b1, b2); |
| cmpRes2 = jit_insn_gt(f, b1, b2); |
| jit_insn_branch_if(f, cmpRes, &falseLabel); |
| jit_insn_branch_if(f, cmpRes2, &trueLabel); |
| } |
| |
| // Decrement loop index |
| temp1 = jit_insn_sub(f, loopIndex, oneJitVal_); |
| jit_insn_store(f, loopIndex, temp1); |
| |
| // Increment string pointers |
| temp2 = jit_insn_add(f, tSrc1, oneJitVal_); |
| temp3 = jit_insn_add(f, tSrc2, oneJitVal_); |
| jit_insn_store(f, tSrc1, temp2); |
| jit_insn_store(f, tSrc2, temp3); |
| |
| // Branch back if loop index <> 0 |
| jit_insn_branch_if(f, loopIndex, &loopLabel); |
| |
| // Usually comparison is followed by branch. Attempt to combine |
| // branches here, so as avoid overhead cost from logical branch. |
| if (!jitProcessPredicate(inst, f, &falseLabel, &trueLabel, |
| dumpTrueBlockFirst)) |
| { |
| if (dumpTrueBlockFirst) { |
| // True block |
| jit_insn_label(f, &trueLabel); |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| |
| // False block |
| jit_insn_label(f, &falseLabel); |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| } |
| else { |
| // False block |
| jit_insn_label(f, &falseLabel); |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| jit_insn_branch(f, &endLabel); |
| |
| // True block |
| jit_insn_label(f, &trueLabel); |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| } |
| |
| // End label |
| jit_insn_label(f, &endLabel); |
| } |
| else |
| skipInst = 1; |
| |
| break; } |
| |
| case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S: |
| case PCIT::NE_MBIN32S_MBIN64S_MBIN64S: |
| { |
| jit_value_t temp1, temp2, temp3; |
| |
| jit_label_t trueLabel = jit_label_undefined; |
| jit_label_t falseLabel = jit_label_undefined; |
| jit_label_t doneLabel = jit_label_undefined; |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| // Need to get pointer to 64-bit vals, since we'll need to perform 2 |
| // 4-byte comparisons. This is done because libjit does not support |
| // comparison of 64-bit types. We can work around this here for EQ/NE |
| // since a memcmp is sufficient to give an answer. |
| src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, block); |
| src2JitVal = src2->getJitValue(this, f, jit_type_void_ptr, block); |
| |
| for (i=0; i < 8; i += 4) { |
| temp1 = jit_insn_load_relative(f, src1JitVal, i, jit_type_uint); |
| temp2 = jit_insn_load_relative(f, src2JitVal, i, jit_type_uint); |
| temp3 = jit_insn_ne(f, temp1, temp2); |
| |
| if (opc == PCIT::EQ_MBIN32S_MBIN64S_MBIN64S) |
| jit_insn_branch_if(f, temp3, &falseLabel); |
| else |
| jit_insn_branch_if(f, temp3, &trueLabel); |
| } |
| |
| // Fall-through implies that the two operands are equal. Generate |
| // the appropriate code, given opc. |
| if (opc == PCIT::EQ_MBIN32S_MBIN64S_MBIN64S) |
| { |
| inst->getWOps()[0]->setJitValue(this, f, oneJitVal_, block); |
| jit_insn_branch(f, &doneLabel); |
| jit_insn_label(f, &falseLabel); |
| inst->getWOps()[0]->setJitValue(this, f, zeroJitVal_, block); |
| } |
| else |
| { |
| inst->getWOps()[0]->setJitValue(this, f, zeroJitVal_, block); |
| jit_insn_branch(f, &doneLabel); |
| jit_insn_label(f, &trueLabel); |
| inst->getWOps()[0]->setJitValue(this, f, oneJitVal_, block); |
| } |
| |
| jit_insn_label(f, &doneLabel); |
| |
| break; |
| } |
| |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_eq(f, src1JitVal, src2JitVal); |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN16U_MBIN16S: |
| case PCIT::LT_MBIN32S_MBIN64S_MBIN64S: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_lt(f, src1JitVal, src2JitVal); |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN16U_MBIN16S: |
| case PCIT::LE_MBIN32S_MBIN64S_MBIN64S: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_le(f, src1JitVal, src2JitVal); |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| |
| |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN16U_MBIN16S: |
| case PCIT::GT_MBIN32S_MBIN64S_MBIN64S: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_gt(f, src1JitVal, src2JitVal); |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16U: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN32U_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN16U_MBIN16S: |
| case PCIT::GE_MBIN32S_MBIN64S_MBIN64S: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_ge(f, src1JitVal, src2JitVal); |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::NE_MBIN32S_MBIN16S_MBIN16S: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_ne(f, src1JitVal, src2JitVal); |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32U: |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32U: |
| { |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| assert (src1->isConst()); |
| |
| // Use the jit type for src2 in both cases, since we checked |
| // before-hand that the type for both are MBIN32U |
| src1JitVal = src1->getJitValue(this, f, src2->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| switch (opc) { |
| case PCIT::EQ_MBIN32S_MBIN16S_MBIN32U: |
| resJitVal = jit_insn_eq(f, src1JitVal, src2JitVal); |
| break; |
| case PCIT::LT_MBIN32S_MBIN16S_MBIN32U: |
| resJitVal = jit_insn_lt(f, src1JitVal, src2JitVal); |
| break; |
| case PCIT::GT_MBIN32S_MBIN16S_MBIN32U: |
| resJitVal = jit_insn_gt(f, src1JitVal, src2JitVal); |
| break; |
| case PCIT::LE_MBIN32S_MBIN16S_MBIN32U: |
| resJitVal = jit_insn_le(f, src1JitVal, src2JitVal); |
| break; |
| case PCIT::GE_MBIN32S_MBIN16S_MBIN32U: |
| resJitVal = jit_insn_ge(f, src1JitVal, src2JitVal); |
| break; |
| } |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MFLT64_MFLT64: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN32S_MBIN32S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S: |
| case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S: |
| { |
| jit_label_t sumLabel = jit_label_undefined; |
| jit_label_t doneLabel = jit_label_undefined; |
| |
| // First check if src is null - if so, we just branch out and return. |
| src2 = inst->getROps()[1]; |
| if (!src2->isConst()) { |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| jit_insn_branch_if(f, src2JitVal, &doneLabel); |
| } |
| else { |
| // Skip check, since constant will be 0 (assert here to verify). |
| } |
| |
| |
| // Let's get the operands now. |
| res = inst->getWOps()[(inst->getWOps()).entries()-1]; |
| src2 = inst->getROps()[(inst->getROps()).entries()-1]; |
| |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| |
| #if 0 |
| // Now check if target is null. If so, we just move the src into tgt. |
| src1 = inst->getROps()[0]; |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| jit_insn_branch_if_not(f, src1JitVal, &sumLabel); |
| |
| |
| // Clear null value of target and clear out it's value. |
| res->storeJitValue(this, f, res->getJitType(), src2JitVal, block); |
| src1->storeNullJitValueAndBranch(this, f, zeroJitVal_, &doneLabel, |
| FALSE, block); |
| |
| |
| // Perform the sum here |
| jit_insn_label(f, &sumLabel); |
| |
| resJitVal = jit_insn_add(f, resJitVal, src2JitVal); |
| res->setJitValue(this, f, resJitVal, block); |
| #else |
| // In an effort to work around a libjit register allocation bug where |
| // the register for the source is overwritten before being added to |
| // the aggregate, we perform the add first (since that's the likely |
| // scenario) and then do the check for null of the aggregate. |
| |
| jit_value_t addJitVal = jit_insn_add(f, resJitVal, src2JitVal); |
| |
| // Now check if target is null. If so, we just move the src into tgt. |
| src1 = inst->getROps()[0]; |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| jit_insn_branch_if_not(f, src1JitVal, &sumLabel); |
| |
| |
| // Clear null value of target and clear out it's value. |
| res->storeJitValue(this, f, res->getJitType(), src2JitVal, block); |
| src1->storeNullJitValueAndBranch(this, f, zeroJitVal_, &doneLabel, |
| FALSE, block); |
| |
| // Store the sum here. |
| jit_insn_label(f, &sumLabel); |
| res->setJitValue(this, f, addJitVal, block); |
| #endif |
| |
| jit_insn_label(f, &doneLabel); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if (opc == PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S) |
| src2->clearJitValues(this); |
| |
| break; |
| } |
| |
| |
| case PCIT::SUM_MFLT64_MFLT64: |
| case PCIT::SUM_MBIN32S_MBIN32S: |
| case PCIT::SUM_MBIN64S_MBIN64S: |
| case PCIT::SUM_MBIN64S_MBIN32S: |
| { |
| res = inst->getWOps()[0]; |
| src1 = res; /* same as write operand */ |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_add(f, src1JitVal, src2JitVal); |
| res->setJitValue(this, f, resJitVal, block); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if (opc == PCIT::SUM_MBIN64S_MBIN32S) |
| src2->clearJitValues(this); |
| |
| break; |
| } |
| |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::ADD_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S: |
| case PCIT::ADD_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S: |
| case PCIT::ADD_MFLT64_MFLT64_MFLT64: |
| { |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_add(f, src1JitVal, src2JitVal); |
| res->setJitValue(this, f, resJitVal, block); |
| |
| if (opc == PCIT::ADD_MFLT64_MFLT64_MFLT64) |
| jitProcessFloatExceptionCheck(f, res, &errorJitLabel, block); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if (opc == PCIT::ADD_MBIN64S_MBIN32S_MBIN64S) |
| src1->clearJitValues(this); |
| |
| break; |
| } |
| |
| /*case PCIT::SUB_MBIN32S_MBIN16S_MBIN16S:*/ |
| case PCIT::SUB_MBIN16S_MBIN16S_MBIN16S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S: |
| case PCIT::SUB_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::SUB_MBIN32S_MBIN32S_MBIN16S: |
| case PCIT::SUB_MFLT64_MFLT64_MFLT64: |
| { |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_sub(f, src1JitVal, src2JitVal); |
| res->setJitValue(this, f, resJitVal, block); |
| |
| if (opc == PCIT::SUB_MFLT64_MFLT64_MFLT64) |
| jitProcessFloatExceptionCheck(f, res, &errorJitLabel, block); |
| |
| // No opt support for this instruction |
| if (opc == PCIT::SUB_MBIN64S_MBIN64S_MBIN64S) |
| lowerOptLevel = TRUE; |
| |
| |
| break; |
| } |
| |
| case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S: |
| case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S: |
| case PCIT::MUL_MFLT64_MFLT64_MFLT64: |
| { |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_mul(f, src1JitVal, src2JitVal); |
| res->setJitValue(this, f, resJitVal, block); |
| |
| if (opc == PCIT::MUL_MFLT64_MFLT64_MFLT64) |
| jitProcessFloatExceptionCheck(f, res, &errorJitLabel, block); |
| |
| break; |
| } |
| |
| case PCIT::DIV_MFLT64_MFLT64_MFLT64: |
| { |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| |
| resJitVal = jit_insn_div(f, src1JitVal, src2JitVal); |
| res->setJitValue(this, f, resJitVal, block); |
| |
| if (opc == PCIT::DIV_MFLT64_MFLT64_MFLT64) |
| jitProcessFloatExceptionCheck(f, res, &errorJitLabel, block); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN32S: |
| { |
| // RETURN instruction must follow |
| assert (inst->next && (inst->next->code[0] == PCIT::RETURN)); |
| |
| jit_label_t l1 = jit_label_undefined; |
| jit_label_t l2 = jit_label_undefined; |
| |
| src1 = inst->getROps()[0]; |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| |
| jit_value_t t1 = jit_insn_eq(f, src1JitVal, oneJitVal_); |
| jit_insn_branch_if(f, t1, &l1); |
| |
| jit_insn_label(f, &l2); |
| jit_insn_return(f, fJitVal_); |
| |
| jit_insn_label(f, &l1); |
| jit_insn_return(f, tJitVal_); |
| |
| break; |
| } |
| |
| case PCIT::RETURN_IBIN32S: |
| { |
| if (inst->code[1] == 1) |
| jit_insn_return(f, tJitVal_); |
| else |
| jit_insn_return(f, fJitVal_); |
| break; |
| } |
| |
| case PCIT::RETURN: |
| { |
| jit_insn_return(f, okJitVal_); |
| break; |
| } |
| |
| // FIX: Bulk instructions can sometimes redefine the operand (because |
| // two moves can be combined into one). So when storeJitValue or |
| // getJitValue is called, the original operand is retrieved, and it's |
| // length is used. Perhaps that should be fixed from the get-go. |
| case PCIT::MOVE_BULK: |
| { |
| CollIndex j, rOps=0, wOps=0; |
| Int32 length = inst->code[1]; |
| |
| // Reload operands to get rid of potential overlapping ones. |
| inst->reloadOperands(this); |
| |
| for (j=3; j != (length-1); j+=3) |
| { |
| Int32 opc = inst->code[j+1]; |
| |
| res = inst->getWOps()[wOps++]; |
| |
| switch(opc) { |
| case PCIT::MOVE_MBIN8_MBIN8_IBIN32S: |
| // This instruction has one more entry (length) in MOVE_BULK. |
| // Advance and then fall-through. |
| j++; |
| |
| case PCIT::MOVE_MBIN64S_MBIN64S: |
| case PCIT::MOVE_MBIN32U_MBIN32U: |
| case PCIT::MOVE_MBIN16U_MBIN16U: |
| case PCIT::MOVE_MBIN8_MBIN8: |
| { |
| src1 = inst->getROps()[rOps++]; |
| |
| src1JitVal = |
| src1->getJitValue(this, f, src1->getJitType(), block); |
| res->storeJitValue(this,f,res->getJitType(),src1JitVal,block); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN16U_IBIN16U: |
| case PCIT::MOVE_MBIN32S_IBIN32S: |
| { |
| type = (opc == PCIT::MOVE_MBIN32S_IBIN32S) |
| ? jit_type_int : jit_type_ushort; |
| |
| Int32 val = inst->code[j+3]; |
| |
| src1JitVal = jit_value_create_nint_constant(f, type, val); |
| res->storeJitValue(this, f, type, src1JitVal, block); |
| |
| break; |
| } |
| |
| default: |
| assert(FALSE); |
| break; |
| } |
| } |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MFLT64_MBIN16S: |
| case PCIT::MOVE_MFLT64_MBIN32S: |
| case PCIT::MOVE_MBIN16U_MBIN8: |
| case PCIT::MOVE_MBIN32U_MBIN16U: |
| case PCIT::MOVE_MBIN32S_MBIN16U: |
| case PCIT::MOVE_MBIN64S_MBIN16U: |
| case PCIT::MOVE_MBIN32U_MBIN16S: |
| case PCIT::MOVE_MBIN32S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN16S: |
| case PCIT::MOVE_MBIN64S_MBIN32U: |
| case PCIT::MOVE_MBIN64S_MBIN32S: |
| { |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src1JitVal = jit_insn_convert(f, src1JitVal, res->getJitType(), 0); |
| res->storeJitValue(this, f, res->getJitType(), src1JitVal, block); |
| |
| // Lastly, clear out jit values for 32-bit source operand if needed. |
| if ((opc == PCIT::MOVE_MBIN64S_MBIN16U) || |
| (opc == PCIT::MOVE_MBIN64S_MBIN16S) || |
| (opc == PCIT::MOVE_MBIN64S_MBIN32U) || |
| (opc == PCIT::MOVE_MBIN64S_MBIN32S)) |
| src1->clearJitValues(this); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN16U_IBIN16U: |
| case PCIT::MOVE_MBIN32S_IBIN32S: |
| { |
| res = inst->getWOps()[0]; |
| type = (opc == PCIT::MOVE_MBIN32S_IBIN32S) |
| ? jit_type_int : jit_type_ushort; |
| |
| Int32 val = inst->code[3]; |
| |
| src1JitVal = jit_value_create_nint_constant(f, type, val); |
| res->storeJitValue(this, f, type, src1JitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::MOVE_MBIN16U_MBIN16U: |
| case PCIT::MOVE_MBIN8_MBIN8: |
| case PCIT::MOVE_MBIN32U_MBIN32U: |
| case PCIT::MOVE_MBIN64S_MBIN64S: |
| case PCIT::MOVE_MBIN8_MBIN8_IBIN32S: |
| { |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| switch(src1->getLen()) { |
| case 1: |
| type = jit_type_ubyte; |
| break; |
| case 2: |
| type = jit_type_ushort; |
| break; |
| case 4: |
| type = jit_type_uint; |
| break; |
| case 8: |
| type = jit_type_long; |
| break; |
| default: |
| { |
| assert (opc == PCIT::MOVE_MBIN8_MBIN8_IBIN32S); |
| type = jit_type_void_ptr; |
| break; |
| } |
| } |
| |
| src1JitVal = src1->getJitValue(this, f, type, block); |
| res->storeJitValue(this, f, type, src1JitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::REPLACE_NULL_MATTR3_MBIN32S: |
| case PCIT::REPLACE_NULL_MATTR3_MBIN32U: |
| case PCIT::REPLACE_NULL_MATTR3_MBIN16S: |
| case PCIT::REPLACE_NULL_MATTR3_MBIN16U: |
| { |
| jit_label_t doneLabel = jit_label_undefined; |
| jit_label_t nullLabel = jit_label_undefined; |
| |
| type = (inst->code[10] == 2) ? jit_type_short : jit_type_int; |
| |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| |
| // Branch if NULL |
| jit_insn_branch_if(f, src1JitVal, &nullLabel); |
| |
| // not null case |
| src2JitVal = inst->getROps()[1]->getJitValue(this, f, type, block); |
| res->storeJitValue(this, f, type, src2JitVal, block); |
| jit_insn_branch(f, &doneLabel); |
| |
| // not null case |
| jit_insn_label(f, &nullLabel); |
| src2JitVal = inst->getROps()[2]->getJitValue(this, f, type, block); |
| res->storeJitValue(this, f, type, src2JitVal, block); |
| |
| jit_insn_label(f, &doneLabel); |
| |
| break; |
| } |
| |
| case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S: |
| { |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| |
| NABoolean testForNull = (inst->code[9] != 0); |
| |
| // Generate more efficient code if next instruction is logical branch |
| if (inst->next && inst->next->isAnyLogicalBranch()) |
| { |
| NABoolean srcLive, tgtLive; |
| |
| PCodeInst* branch = inst->next; |
| |
| PCodeOperand* bSrc = branch->getROps()[0]; |
| PCodeOperand* bTgt = branch->getWOps()[0]; |
| |
| // Is source or target live after branch? |
| srcLive = bSrc->isVar() || block->isOperandLiveInSuccs(bSrc); |
| tgtLive = bTgt->isVar() || block->isOperandLiveInSuccs(bTgt); |
| |
| // Only generate efficient path if the null-test is associated with |
| // the branch, and that both the src and tgt of the branch are not |
| // live (which would otherwise require one or more stores). |
| if ((bSrc->getBvIndex()==res->getBvIndex()) && !srcLive && !tgtLive) |
| { |
| jitLabel = block->getTargetBlock()->getJitLabel(); |
| |
| // Branch to destination according to the test performed. |
| switch (branch->getOpcode()) { |
| case PCIT::BRANCH_OR: |
| case PCIT::BRANCH_OR_CNT: |
| if (testForNull) |
| jit_insn_branch_if(f, src1JitVal, jitLabel); |
| else |
| jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| break; |
| |
| case PCIT::BRANCH_AND: |
| case PCIT::BRANCH_AND_CNT: |
| if (testForNull) |
| jit_insn_branch_if_not(f, src1JitVal, jitLabel); |
| else |
| jit_insn_branch_if(f, src1JitVal, jitLabel); |
| break; |
| } |
| |
| // Skip the next instruction (branch) since it was handled here. |
| skipInst = 1; |
| break; |
| } |
| } |
| else if (inst->next && inst->next->getOpcode() == PCIT::MOVE_MBIN32S) |
| { |
| PCodeInst* move = inst->next; |
| if (res->getBvIndex() == move->getROps()[0]->getBvIndex()) |
| { |
| jit_label_t l1 = jit_label_undefined; |
| |
| // A RETURN is guaranteed to following a MOVE_MBIN32S |
| assert (move->next && (move->next->getOpcode() == PCIT::RETURN)); |
| |
| if (testForNull) |
| jit_insn_branch_if(f, src1JitVal, &l1); |
| else |
| jit_insn_branch_if_not(f, src1JitVal, &l1); |
| |
| jit_insn_return(f, fJitVal_); |
| |
| jit_insn_label(f, &l1); |
| jit_insn_return(f, tJitVal_); |
| |
| // Skip the next 2 instructions since it was handled here. |
| skipInst = 2; |
| break; |
| } |
| } |
| |
| // Fall-through (default) case to implement NULL_TEST |
| |
| if (testForNull) |
| resJitVal = jit_insn_ne(f, src1JitVal, zeroJitVal_); |
| else |
| resJitVal = jit_insn_eq(f, src1JitVal, zeroJitVal_); |
| |
| inst->getWOps()[0]->setJitValue(this, f, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::STRLEN_MBIN32U_MATTR5: |
| { |
| jit_type_t vcType; |
| jit_value_t vcLenJitVal; |
| |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| if (src1->getVcIndicatorLen() == 2) { |
| vcType = jit_type_ushort; |
| vcLenJitVal = jit_value_create_nint_constant(f, jit_type_int, 2); |
| } |
| else { |
| vcType = jit_type_uint; |
| vcLenJitVal = jit_value_create_nint_constant(f, jit_type_int, 4); |
| } |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| resJitVal = jit_insn_load_relative(f, src1JitVal, 0, vcType); |
| |
| // If length is 2 bytes, then convert it to 4 bytes before storage |
| if (src1->getVcIndicatorLen() == 2) |
| resJitVal = jit_insn_convert(f, resJitVal, jit_type_int, 0); |
| |
| res->storeJitValue(this, f, jit_type_int, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::POS_MBIN32S_MATTR5_MATTR5: |
| { |
| break; |
| } |
| |
| case PCIT::AND_MBIN32S_MBIN32S_MBIN32S: |
| { |
| jit_label_t ret0Label = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| |
| res = inst->getWOps()[0]; |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, jit_type_int, block); |
| src2JitVal = src2->getJitValue(this, f, jit_type_int, block); |
| |
| resJitVal = jit_insn_and(f, src1JitVal, src2JitVal); |
| jit_insn_branch_if_not(f, resJitVal, &ret0Label); |
| |
| resJitVal = jit_insn_or(f, src1JitVal, src2JitVal); |
| res->storeJitValue(this, f, jit_type_int, resJitVal, block); |
| jit_insn_branch(f, &endLabel); |
| |
| jit_insn_label(f, &ret0Label); |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, block); |
| |
| jit_insn_label(f, &endLabel); |
| |
| break; |
| } |
| |
| case PCIT::OR_MBIN32S_MBIN32S_MBIN32S: |
| { |
| jit_value_t t1, t2; |
| |
| jit_label_t ret1Label = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| |
| res = inst->getWOps()[0]; |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, jit_type_int, block); |
| t1 = jit_insn_eq(f, src1JitVal, oneJitVal_); |
| |
| src2JitVal = src2->getJitValue(this, f, jit_type_int, block); |
| t2 = jit_insn_eq(f, src2JitVal, oneJitVal_); |
| |
| resJitVal = jit_insn_or(f, t1, t2); |
| jit_insn_branch_if(f, resJitVal, &ret1Label); |
| |
| resJitVal = jit_insn_or(f, src1JitVal, src2JitVal); |
| res->storeJitValue(this, f, jit_type_int, resJitVal, block); |
| jit_insn_branch(f, &endLabel); |
| |
| jit_insn_label(f, &ret1Label); |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, block); |
| |
| jit_insn_label(f, &endLabel); |
| |
| break; |
| } |
| |
| case PCIT::MINMAX_MBIN8_MBIN8_MBIN32S_IBIN32S: |
| { |
| jit_type_t type; |
| jit_label_t doneLabel = jit_label_undefined; |
| |
| src1 = inst->getROps()[0]; // Source pointer |
| src2 = inst->getROps()[1]; // Result of comparison |
| |
| res = inst->getWOps()[0]; |
| |
| src2JitVal = src2->getJitValue(this, f, jit_type_int, block); |
| |
| jit_insn_branch_if_not(f, src2JitVal, &doneLabel); |
| |
| // Get type associated with length, since generic MBINS is used to |
| // represent source/tgt. If not, getJitType() is called, and it will |
| // assume we're dealing with a void ptr by default. |
| |
| switch(src1->getLen()) { |
| case 1: |
| type = jit_type_ubyte; |
| break; |
| case 2: |
| type = jit_type_ushort; |
| break; |
| case 4: |
| type = jit_type_uint; |
| break; |
| case 8: |
| type = jit_type_long; |
| break; |
| default: |
| { |
| type = jit_type_void_ptr; |
| break; |
| } |
| } |
| |
| src1JitVal = src1->getJitValue(this, f, type, block); |
| res->setJitValue(this, f, src1JitVal, block); |
| |
| jit_insn_label(f, &doneLabel); |
| |
| break; |
| } |
| |
| case PCIT::SWITCH_MBIN32S_MBIN64S_MPTR32_IBIN32S_IBIN32S: |
| { |
| jit_value_t t1, t2, t3, t4, t5, t6, t7, tableEnd; |
| |
| jit_label_t startLoop = jit_label_undefined; |
| jit_label_t trueLabel = jit_label_undefined; |
| jit_label_t falseLabel = jit_label_undefined; |
| |
| jit_value_t hashTableJitVal; |
| |
| jit_value_t invalidInt32JitVal = |
| jit_value_create_nint_constant(f, jit_type_uint, INVALID_INT32); |
| |
| jit_value_t hashTableSizeJitVal = |
| jit_value_create_nint_constant(f, jit_type_uint, inst->code[7]); |
| |
| // 1. Get the 64-bit value and hash it. |
| // 2. Take result and mod it by size of hash table. |
| // 3. Start loop |
| // 4. Get element and compare to INVALID_INT64 (maybe just INT32?) |
| // 5. If EQUAL - compare value with source |
| // 6. If EQUAL - store 1 |
| // 7. ELSE: Increment index by 1 and compare with size |
| // 8. If beyond table size, store 0 |
| // 9. ELSE: Jump back to loop header |
| // 9. ELSE: store 0 |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| res = inst->getWOps()[0]; |
| |
| // Step 1 |
| src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, block); |
| resJitVal = genHash(f, src1JitVal, NULL, loopIndex, 8); |
| |
| // Step 2 |
| resJitVal = jit_insn_rem(f, resJitVal, hashTableSizeJitVal); |
| |
| // Step 3-4 |
| hashTableJitVal=src2->getJitValue(this, f, src2->getJitType(), block); |
| resJitVal = jit_insn_load_elem_address(f, hashTableJitVal, resJitVal, |
| jit_type_ulong); |
| |
| // End of table is basically "size" * "sizeof(Int64)". |
| tableEnd = jit_insn_add_relative(f, hashTableJitVal, 8*inst->code[7]); |
| |
| // Load the 8 bytes associated with the source before the loop |
| t6 = jit_insn_load_relative(f, src1JitVal, 0, jit_type_uint); |
| t7 = jit_insn_load_relative(f, src1JitVal, 4, jit_type_uint); |
| |
| jit_insn_label(f, &startLoop); |
| |
| t1 = jit_insn_load_relative(f, resJitVal, 0, jit_type_uint); |
| t2 = jit_insn_load_relative(f, resJitVal, 4, jit_type_uint); |
| t3 = jit_insn_eq(f, t1, invalidInt32JitVal); |
| t4 = jit_insn_eq(f, t2, invalidInt32JitVal); |
| t5 = jit_insn_and(f, t3, t4); |
| |
| jit_insn_branch_if(f, t5, &falseLabel); |
| |
| // Step 5-6 |
| |
| t3 = jit_insn_eq(f, t1, t6); |
| t4 = jit_insn_eq(f, t2, t7); |
| t5 = jit_insn_and(f, t3, t4); |
| jit_insn_branch_if(f, t5, &trueLabel); |
| |
| // Step 7 |
| t6 = jit_insn_add_relative(f, resJitVal, 8); |
| jit_insn_store(f, resJitVal, t6); |
| |
| t4 = jit_insn_eq(f, t6, tableEnd); |
| jit_insn_branch_if_not(f, t4, &startLoop); |
| |
| if (!jitProcessPredicate(inst, f, &falseLabel, &trueLabel, FALSE)) { |
| assert(FALSE); |
| } else |
| skipInst = 1; |
| |
| // Libjit bad -O2 code gen when remainder generated with constants. |
| lowerOptLevel = TRUE; |
| |
| break; |
| } |
| |
| |
| case PCIT::SWITCH_MBIN32S_MATTR5_MPTR32_IBIN32S_IBIN32S: |
| { |
| jit_value_t t1, t2, t3, t4, t5, tableEnd; |
| jit_value_t len = NULL; |
| |
| jit_label_t startLoop = jit_label_undefined; |
| jit_label_t trueLabel = jit_label_undefined; |
| jit_label_t falseLabel = jit_label_undefined; |
| jit_label_t tryAgainLabel = jit_label_undefined; |
| |
| jit_value_t hashTableJitVal; |
| |
| jit_value_t invalidInt32JitVal = |
| jit_value_create_nint_constant(f, jit_type_uint, INVALID_INT32); |
| |
| jit_value_t hashTableSizeJitVal = |
| jit_value_create_nint_constant(f, jit_type_uint, inst->code[10]); |
| |
| // 1. Get the string value (minus any padding) and hash it. |
| // 2. Take result and mod it by size of hash table. |
| // 3. Start loop |
| // 4. Get element and compare to INVALID_INT32 |
| // 5. If EQUAL - compare string with source |
| // 6. If EQUAL - store 1 |
| // 7. ELSE: Increment index by 1 and compare with size |
| // 8. If beyond table size, store 0 |
| // 9. ELSE: Jump back to loop header |
| // 9. ELSE: store 0 |
| |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| res = inst->getWOps()[0]; |
| |
| // Step 1 |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| len = genStringSetup(f, &src1JitVal, src1, TRUE); |
| |
| jit_insn_store(f, tSrc1, src1JitVal); |
| resJitVal = genHash(f, tSrc1, len, loopIndex, src1->getLen()); |
| |
| // Step 2 |
| resJitVal = jit_insn_rem(f, resJitVal, hashTableSizeJitVal); |
| |
| // Step 3-4 |
| hashTableJitVal=src2->getJitValue(this, f, src2->getJitType(), block); |
| resJitVal = jit_insn_load_elem_address(f, hashTableJitVal, resJitVal, |
| jit_type_ulong); |
| |
| // End of table is basically "size" * "sizeof(Int64)". |
| tableEnd = jit_insn_add_relative(f, hashTableJitVal,8*inst->code[10]); |
| |
| jit_insn_label(f, &startLoop); |
| |
| t1 = jit_insn_load_relative(f, resJitVal, 0, jit_type_uint); |
| t3 = jit_insn_eq(f, t1, invalidInt32JitVal); |
| jit_insn_branch_if(f, t3, &falseLabel); |
| |
| // Step 5-6 |
| t4 = jit_insn_ne(f, t1, len); |
| jit_insn_branch_if(f, t4, &tryAgainLabel); |
| |
| // Set up arguments and make indirect call to str_cmp routine. |
| t2 = jit_insn_load_relative(f, resJitVal, 4, jit_type_uint); |
| src2JitVal = |
| jit_insn_load_elem_address(f, jitParams_[1], t2, jit_type_ubyte); |
| |
| jit_value_t args[3] = {src1JitVal, src2JitVal, len}; |
| t1 = jit_insn_call_indirect(f, strcmpJitVal, |
| strcmpSig, args, 3, 0); |
| |
| jit_insn_branch_if_not(f, t1, &trueLabel); |
| |
| // Step 7 |
| jit_insn_label(f, &tryAgainLabel); |
| |
| t5 = jit_insn_add_relative(f, resJitVal, 8); |
| jit_insn_store(f, resJitVal, t5); |
| |
| t4 = jit_insn_eq(f, t5, tableEnd); |
| jit_insn_branch_if_not(f, t4, &startLoop); |
| |
| if (!jitProcessPredicate(inst, f, &falseLabel, &trueLabel, FALSE)) { |
| assert(FALSE); |
| } else { |
| //FIXME: we may skip more than 1 inst if next inst is a MOVE_MBIN32S |
| skipInst = 1; |
| } |
| |
| // Libjit bad -O2 code gen when remainder generated with constants. |
| lowerOptLevel = TRUE; |
| |
| break; |
| } |
| |
| case PCIT::HASHCOMB_BULK_MBIN32U: |
| { |
| jit_value_t t3, t4, t5, oldResJitVal = NULL; |
| |
| res = inst->getWOps()[0]; |
| |
| // The list of source operands come in potentially rearranged, so that |
| // the parallel hash algorithm could run through this faster. But |
| // with native exprs, we do not call hashP, and so we need to hash |
| // the source operands in order. Re-re-arrange them :). |
| |
| OPLIST origList; // List of operands in order. |
| |
| Int32 min = 0; // first position to start off is 0. |
| CollIndex length = inst->code[1]; // Total length of instruction. |
| |
| // Walk through instruction (skipping header stuff) and identify the |
| // source operand having the "min" position. Once found, insert it |
| // into the origList, and then restart check with "min" set to the |
| // next position. |
| |
| for (j=4; j < length;) { |
| if (inst->code[j+3] == min) { |
| // Add the appropriate source to the list |
| origList.insert(inst->getROps()[(j >> 2) - 1]); |
| |
| // Get the next min position, and restart by setting j to 4; |
| min++; |
| j = 4; |
| } |
| else { |
| // Move to the next source. |
| j += 4; |
| } |
| } |
| |
| assert (inst->getROps().entries() == origList.entries()); |
| |
| for (j=0; j < origList.entries(); j++) { |
| src1 = origList[j]; |
| Int32 len = src1->getLen(); |
| |
| // If the source length is 0, then the source represents the result |
| // of a previously computed hash instruction. Otherwise, get the |
| // source as a pointer and call genHash to get the result. |
| if (len > 0) { |
| src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, block); |
| resJitVal = genHash(f, src1JitVal, NULL, loopIndex, len); |
| } |
| else |
| resJitVal = src1->getJitValue(this, f, jit_type_uint, block); |
| |
| // Combine previous hash results if this is not the 1st run through. |
| if (j > 0) { |
| // |
| // Hashcomb is performed similarly to how Hash is performed - see |
| // PCodeCfg::genHash() |
| // |
| // Compute: t3 = oldResJitVal << 1 |
| // t4 = oldResJitVal >> 31 |
| // t5 = (t3 | t4) |
| // resJitVal = t5 ^ resJitVal |
| // |
| |
| t3 = jit_insn_shl(f, oldResJitVal, oneJitVal_); |
| t4 = jit_insn_ushr(f, oldResJitVal, shiftRVal); |
| t5 = jit_insn_or(f, t3, t4); |
| |
| resJitVal = jit_insn_xor(f, t5, resJitVal); |
| } |
| |
| oldResJitVal = resJitVal; |
| } |
| |
| res->storeJitValue(this, f, jit_type_uint, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::HASH_MBIN32U_MATTR5: |
| case PCIT::HASH_MBIN32U_MPTR32_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN16_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN32_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN64_IBIN32S_IBIN32S: |
| { |
| jit_value_t len = NULL; |
| |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| // Need to get pointer to operands |
| src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, block); |
| |
| // Get length and setup string if we're hashing a varchar. |
| if (opc == PCIT::HASH_MBIN32U_MATTR5) |
| len = genStringSetup(f, &src1JitVal, src1, TRUE); |
| |
| resJitVal = genHash(f, src1JitVal, len, loopIndex, src1->getLen()); |
| |
| res->storeJitValue(this, f, jit_type_uint, resJitVal, block); |
| |
| break; |
| } |
| |
| case PCIT::RANGE_MFLT64: |
| { |
| break; |
| } |
| |
| #if 0 |
| case PCIT::HASH_MBIN32U_MPTR32_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN16_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN32_IBIN32S_IBIN32S: |
| case PCIT::HASH_MBIN32U_MBIN64_IBIN32S_IBIN32S: |
| { |
| jit_value_t t1, t2, t3, t4, t5; |
| |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| Int32 j, len = src1->getLen(); |
| |
| // Need to get pointers to operands |
| src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, block); |
| |
| // Handles fixed-length strings, but let's not do all of them now. |
| if (len > 2000) |
| assert(FALSE); |
| |
| t1 = jit_insn_load_relative(f, src1JitVal, 0, jit_type_ubyte); |
| resJitVal = jit_insn_load_elem(f, hashTableJitVal_, t1, |
| jit_type_uint); |
| |
| // Unroll hash using known length |
| for (j=1; j < len; j++) |
| { |
| // |
| // Compute: t1 = src[j] |
| // t2 = randomHashValues[t1] |
| // t3 = resJitVal << 1 |
| // t4 = resJitVal >> 31 |
| // t5 = (t3 | t4) |
| // resJitVal = t5 ^ resJitVal |
| // |
| t1 = jit_insn_load_relative(f, src1JitVal, j, jit_type_ubyte); |
| t2 = jit_insn_load_elem(f, hashTableJitVal_, t1, jit_type_uint); |
| t3 = jit_insn_shl(f, resJitVal, oneJitVal_); |
| t4 = jit_insn_ushr(f, resJitVal, shiftRVal); |
| t5 = jit_insn_or(f, t3, t4); |
| resJitVal = jit_insn_xor(f, t5, t2); |
| } |
| |
| res->storeJitValue(this, f, jit_type_uint, resJitVal, block); |
| |
| break; |
| } |
| #endif |
| |
| case PCIT::SUB_MBIGS_MBIGS_MBIGS_IBIN32S: |
| { |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| jit_value_t lenJitVal = |
| jit_value_create_nint_constant(f, jit_type_int, src1->getLen()); |
| |
| // Need to get pointers to operands |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| |
| // Set up arguments and make indirect call to compare routine. |
| jit_value_t args[4] = {resJitVal, src1JitVal, src2JitVal, lenJitVal}; |
| resJitVal = jit_insn_call_indirect(f, bigSubJitVal, |
| bigSig, args, 4, 0); |
| |
| jit_insn_branch_if(f, resJitVal, &errorJitLabel); |
| |
| break; |
| } |
| |
| case PCIT::ADD_MBIGS_MBIGS_MBIGS_IBIN32S: |
| { |
| jit_label_t fastPathLabel = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| jit_value_t t1, t2, t3, t4, t5, carry = NULL; |
| |
| res = inst->getWOps()[0]; |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| |
| Int32 len = src1->getLen(); |
| |
| // Need to get pointers to operands |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| |
| // Get sign bits. No need to clear (I think) |
| if ((len % 4) == 0) { |
| t1=jit_insn_load_relative(f, src1JitVal, (len>>2)-1,jit_type_uint); |
| t2=jit_insn_load_relative(f, src2JitVal, (len>>2)-1,jit_type_uint); |
| t3=jit_insn_and(f, t1, jitValMask32); |
| t4=jit_insn_and(f, t2, jitValMask32); |
| } |
| else { |
| t1=jit_insn_load_relative(f, src1JitVal,(len>>1)-1,jit_type_ushort); |
| t2=jit_insn_load_relative(f, src2JitVal,(len>>1)-1,jit_type_ushort); |
| t3=jit_insn_and(f, t1, jitValMask16); |
| t4=jit_insn_and(f, t2, jitValMask16); |
| } |
| t5 = jit_insn_eq(f, t3, t4); |
| jit_insn_branch_if(f, t5, &fastPathLabel); |
| |
| // Call subtract function here. |
| genBignumSub(this, f, res, src1JitVal, src2JitVal, t1, t2, tSrc1, |
| tSrc2, block); |
| |
| jit_insn_branch(f, &endLabel); |
| |
| |
| // |
| // Fast path. Here's the algorithm: |
| // |
| // 1. Add each 16-bit value of the bignum and carry over remainder |
| // 2. Ignore (and don't record) remainder for last addition |
| // 3. Get sign of src1/src2 and use it to set sign of target. |
| // |
| |
| jit_insn_label(f, &fastPathLabel); |
| |
| for (i=0; i < len; i+=2) |
| { |
| t1 = jit_insn_load_relative(f, src1JitVal, i, jit_type_ushort); |
| t2 = jit_insn_load_relative(f, src2JitVal, i, jit_type_ushort); |
| t3 = jit_insn_add(f, t1, t2); |
| |
| if (i != 0) |
| t3 = jit_insn_add(f, t3, carry); |
| |
| t4 = jit_insn_convert(f, t3, jit_type_ushort, 0); |
| |
| // Process the last short with the sign bit differently. |
| if (i == (len - 2)) { |
| jit_value_t clear1 = jit_insn_and(f, t4, jitValNotMask16); |
| jit_value_t get1 = jit_insn_and(f, t1, jitValMask16); |
| t4 = jit_insn_or(f, clear1, get1); |
| jit_insn_store_relative(f, resJitVal, i, t4); |
| } |
| else { |
| jit_insn_store_relative(f, resJitVal, i, t4); |
| carry = jit_insn_ushr(f, t3, jitVal16); |
| } |
| } |
| |
| jit_insn_label(f, &endLabel); |
| |
| break; |
| } |
| |
| case PCIT::OPDATA_MPTR32_IBIN32S: |
| case PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S: |
| case PCIT::OPDATA_MBIN16U_IBIN32S: |
| case PCIT::OPDATA_MATTR5_IBIN32S: |
| { |
| OPLIST opList = |
| (inst->getWOps().entries() ? inst->getWOps() : inst->getROps()); |
| |
| Int32 index = |
| (opc == PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S) ? inst->code[4] |
| : ((opc == PCIT::OPDATA_MATTR5_IBIN32S) ? inst->code[6] |
| : inst->code[3]); |
| |
| // Add the "correct" operand for this opdata instruction, replacing |
| // the old one in the operand list used during pcode opts. |
| setupClauseOperand(this, opList, opData, index, inst->clause_); |
| |
| break; |
| } |
| |
| case PCIT::CLAUSE_EVAL: |
| { |
| jit_label_t doneLabel = jit_label_undefined; |
| jit_label_t trueLabel = jit_label_undefined; |
| jit_label_t falseLabel = jit_label_undefined; |
| jit_label_t nullLabel = jit_label_undefined; |
| |
| // on 64-bit the clause pointer is in code[1] and code[2] |
| ex_clause* clause = (ex_clause*)*(Long*)&(inst->code[1]); |
| NABoolean processNulls = inst->code[1 + PCODEBINARIES_PER_PTR]; |
| |
| switch (clause->getClassID()) { |
| case ex_clause::AGGR_MIN_MAX_ID: |
| { |
| // |
| // Format: |
| // |
| // attr[0] - Aggregate |
| // attr[1] - Column |
| // attr[2] - Comparison result |
| // |
| |
| // First branch away if comp result indicates no update needed. |
| // Note, since this check is always made, the jit value from the |
| // null-check can be used outside of the CLAUSE_EVAL. |
| src2 = opDataVals[2]; |
| src2JitVal = src2->getJitValue(this, f, jit_type_int, block); |
| jit_insn_branch_if_not(f, src2JitVal, &doneLabel); |
| |
| // We need to copy over source into aggregate. First take care of |
| // the null indicator if the aggregate is nullable. |
| if (clause->getOperand(0)->getNullFlag()) { |
| // If column is nullable too, then we need to check it. If it's |
| // NULL, we don't do anything. |
| |
| if (clause->getOperand(1)->getNullFlag()) { |
| src1 = opDataNulls[1]; |
| src1JitVal = |
| src1->getJitValue(this, f, src1->getJitType(), block, |
| NULL, TRUE /* no assign jit val */); |
| |
| jit_insn_branch_if(f, src1JitVal, &doneLabel); |
| } |
| |
| // Null out the null indicator for the aggregate. Based on the |
| // current code, the null indicator for the aggregate is always |
| // in exploded format, so assert that here and then simplify |
| // code generation. |
| assert(!opDataNulls[0]->forAlignedFormat()); |
| |
| opDataNulls[0]->setJitValue(this, f, zeroJitVal16, block, TRUE); |
| } |
| |
| // Now we have to handle moving the data over from column to aggr. |
| res = opDataVals[0]; |
| src1 = opDataVals[1]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), |
| block, NULL, TRUE /* no assign */); |
| |
| if (res->isVarchar()) |
| { |
| // The following code was taken from MOVE_MATTR5_MATTR5, but |
| // re-formatted here. |
| jit_type_t vcType; |
| jit_value_t vcLenJitVal; |
| |
| if (src1->getVcIndicatorLen() == 2) { |
| vcType = jit_type_ushort; |
| vcLenJitVal=jit_value_create_nint_constant(f, jit_type_int,2); |
| } |
| else { |
| vcType = jit_type_uint; |
| vcLenJitVal=jit_value_create_nint_constant(f, jit_type_int,4); |
| } |
| |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block, |
| NULL, TRUE /* no assign */); |
| |
| jit_insn_store(f, tRes, resJitVal); |
| jit_insn_store(f, tSrc1, src1JitVal); |
| |
| jit_value_t srcLen = |
| jit_insn_load_relative(f, src1JitVal, 0, vcType); |
| |
| srcLen = jit_insn_add(f, srcLen, vcLenJitVal); |
| |
| genUnalignedMemcpy(f, tRes, tSrc1, srcLen); |
| } |
| else |
| res->storeJitValue(this, f, res->getJitType(),src1JitVal, |
| block, NULL, TRUE); |
| |
| // Reached the end point |
| jit_insn_label(f, &doneLabel); |
| |
| break; |
| } |
| |
| case ex_clause::COMP_TYPE: |
| { |
| switch (((ex_comp_clause*)clause)->getInstruction()) { |
| case NE_DATETIME_DATETIME: |
| case EQ_DATETIME_DATETIME: |
| case LT_DATETIME_DATETIME: |
| case GT_DATETIME_DATETIME: |
| case LE_DATETIME_DATETIME: |
| case GE_DATETIME_DATETIME: |
| { |
| jit_value_t year1, year2; |
| |
| res = opDataVals[0]; |
| src1 = opDataVals[1]; |
| src2 = opDataVals[2]; |
| |
| src1JitVal = src1->getJitValue(this, f, jit_type_void_ptr, |
| block, NULL); |
| src2JitVal = src2->getJitValue(this, f, jit_type_void_ptr, |
| block, NULL); |
| if (processNulls) { |
| PCodeOperand* nullOp; |
| jit_value_t nullJitVal; |
| |
| if (clause->getOperand(1)->getNullFlag()) { |
| nullOp = opDataNulls[1]; |
| nullJitVal = |
| nullOp->getJitValue(this, f, nullOp->getJitType(), block, |
| NULL, TRUE /* no assign jit val */); |
| |
| jit_insn_branch_if(f, nullJitVal, &nullLabel); |
| } |
| |
| if (clause->getOperand(2)->getNullFlag()) { |
| nullOp = opDataNulls[2]; |
| nullJitVal = |
| nullOp->getJitValue(this, f, nullOp->getJitType(), block, |
| NULL, TRUE /* no assign jit val */); |
| |
| jit_insn_branch_if(f, nullJitVal, &nullLabel); |
| } |
| } |
| |
| long dtCode = |
| ((ExpDatetime*)(clause->getOperand(1)))->getPrecision(); |
| |
| switch (dtCode) |
| { |
| case REC_DTCODE_TIME: |
| case REC_DTCODE_DATE: |
| case REC_DTCODE_TIMESTAMP: |
| { |
| // Boolean used to indicate whether branch should go to |
| // true block or not. Assume "not" by default. |
| NABoolean dumpTrueBlockFirst = TRUE; // May change later |
| |
| Int32 size = (clause->getOperand(1))->getLength(); |
| |
| // Cycle through each field in the date-related struct. |
| Int32 typeSize = 0; |
| for (i=0; i < size; i += typeSize) |
| { |
| jit_type_t type; |
| |
| // Are we getting the fractional seconds? |
| if ((i == size-4) && (dtCode == REC_DTCODE_TIMESTAMP)) { |
| type = jit_type_uint; |
| typeSize = 4; |
| } |
| // Are we getting the year? |
| else if ((i==0) && (dtCode != REC_DTCODE_TIME)) { |
| type = jit_type_ushort; |
| typeSize = 2; |
| } |
| // We're just getting some particular byte field |
| else { |
| type = jit_type_ubyte; |
| typeSize = 1; |
| } |
| |
| // Get the fields from both sources. |
| year1 = jit_insn_load_relative(f, src1JitVal, i, type); |
| year2 = jit_insn_load_relative(f, src2JitVal, i, type); |
| |
| // Depending on the comparison being performed, generate |
| // 1 (or 2) compares and branches. Also, based on the |
| // comparison, the fall-through may be the "true" block, |
| // or it may be the "false" block - default is TRUE. |
| |
| switch (((ex_comp_clause*)clause)->getInstruction()) { |
| case NE_DATETIME_DATETIME: |
| resJitVal = jit_insn_ne(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &trueLabel); |
| dumpTrueBlockFirst = FALSE; |
| break; |
| case EQ_DATETIME_DATETIME: |
| resJitVal = jit_insn_ne(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &falseLabel); |
| break; |
| case LT_DATETIME_DATETIME: |
| resJitVal = jit_insn_lt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &trueLabel); |
| resJitVal = jit_insn_gt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &falseLabel); |
| dumpTrueBlockFirst = FALSE; |
| break; |
| case GT_DATETIME_DATETIME: |
| resJitVal = jit_insn_gt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &trueLabel); |
| resJitVal = jit_insn_lt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &falseLabel); |
| dumpTrueBlockFirst = FALSE; |
| break; |
| case LE_DATETIME_DATETIME: |
| resJitVal = jit_insn_lt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &trueLabel); |
| resJitVal = jit_insn_gt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &falseLabel); |
| break; |
| case GE_DATETIME_DATETIME: |
| resJitVal = jit_insn_gt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &trueLabel); |
| resJitVal = jit_insn_lt(f, year1, year2); |
| jit_insn_branch_if(f, resJitVal, &falseLabel); |
| break; |
| } |
| } |
| |
| if (!dumpTrueBlockFirst) |
| { |
| // False label first. |
| jit_insn_label(f, &falseLabel); |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, |
| block); |
| jit_insn_branch(f, &doneLabel); |
| |
| // True label next. |
| jit_insn_label(f, &trueLabel); |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, |
| block); |
| jit_insn_branch(f, &doneLabel); |
| } |
| else { |
| // True label first. |
| jit_insn_label(f, &trueLabel); |
| res->storeJitValue(this, f, jit_type_int, oneJitVal_, |
| block); |
| jit_insn_branch(f, &doneLabel); |
| |
| // False label next. |
| jit_insn_label(f, &falseLabel); |
| res->storeJitValue(this, f, jit_type_int, zeroJitVal_, |
| block); |
| jit_insn_branch(f, &doneLabel); |
| } |
| |
| // Null label last. |
| jit_insn_label(f, &nullLabel); |
| res->storeJitValue(this,f,jit_type_int,neg1JitVal_,block); |
| |
| jit_insn_label(f, &doneLabel); |
| |
| break; |
| } |
| |
| default: |
| assert(FALSE); |
| } |
| break; |
| } |
| } |
| |
| break; |
| } |
| } |
| |
| // Clear out opData for subsequent use. |
| str_pad((char*)opData, |
| (3*ex_clause::MAX_OPERANDS)*sizeof(PCodeOperand*), 0); |
| |
| break; |
| } |
| |
| #if 0 |
| // |
| // SUBSTR should be completely implemented, but I don't recall if it |
| // was properly tested. Also, SUBSTR should be improved such that if |
| // the result is to a temp operand, then modify the temp such that it |
| // serves really as a pointer to a string, and not the string itself, |
| // such that the computation needed would just be a) storage of the |
| // variable length (if varchar), and b) the pointer to the start of the |
| // substring. This will save on unnecessary string copies. |
| case PCIT::SUBSTR_MATTR5_MATTR5_MBIN32S_MBIN32S: |
| { |
| jit_value_t strLen, tgtLen, cmpVal, startPosVal, forLenVal; |
| jit_label_t legitStartLabel = jit_label_undefined; |
| jit_label_t startCopyLabel = jit_label_undefined; |
| jit_label_t doneLabel = jit_label_undefined; |
| Int32 startPos, totalLen=0, forLen=0; |
| |
| // Get operands |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| // Get start position and forLen (if provided) |
| startPos = getIntConstValue(inst->getROps()[1]); |
| if (inst->getROps().entries() == 3) |
| forLen = getIntConstValue(inst->getROps()[2]); |
| |
| // Set up src1 string and length |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| strLen = genStringSetup(f, &src1JitVal, src1); |
| |
| // Let's set up the src1JitVal pointer to the start position. |
| startPosVal = |
| jit_value_create_nint_constant(f, jit_type_int, startPos-1); |
| src1JitVal = jit_insn_add(f, src1JitVal, startPosVal); |
| |
| // If we're dealing with a varchar, do checks at run-time, and then |
| // generate copy to completion. |
| if (src1->isVarchar()) |
| { |
| // Set up value that is used to record length to copy |
| jit_value_t subLenVal = jit_value_create(f, jit_type_int); |
| |
| // 1. If start > strLen, return empty string. |
| cmpVal = jit_insn_lt(f, startPosVal, strLen); |
| jit_insn_branch_if(f, cmpVal, &legitStartLabel); |
| |
| jit_insn_store(f, subLenVal, zeroJitVal_); |
| jit_insn_branch(f, &startCopyLabel); |
| |
| jit_insn_label(f, &legitStartLabel); |
| |
| // 2. Calculate max # of chars to copy |
| if (startPos == 1) |
| tgtLen = strLen; |
| else { |
| jit_value_t tVal = |
| jit_value_create_nint_constant(f, jit_type_int, 1-startPos); |
| tgtLen = jit_insn_add(f, strLen, tVal); |
| } |
| |
| jit_insn_store(f, subLenVal, tgtLen); |
| |
| // 3. If a forLen was provided, tgtLen = min (tgtLen, forLen) |
| if (forLen) { |
| forLenVal = jit_value_create_nint_constant(f,jit_type_int,forLen); |
| |
| cmpVal = jit_insn_ge(f, forLenVal, tgtLen); |
| jit_insn_branch_if(f, cmpVal, &startCopyLabel); |
| |
| jit_insn_store(f, subLenVal, forLenVal); |
| } |
| |
| jit_insn_label(f, &startCopyLabel); |
| |
| // Get result string. Store length first before setting the string |
| // up. The result length does not need to be retrieved. |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| if (res->getVcIndicatorLen() == 2) |
| tgtLen = jit_insn_convert(f, subLenVal, jit_type_ushort, 0); |
| else |
| tgtLen = jit_insn_convert(f, subLenVal, jit_type_uint, 0); |
| |
| jit_insn_store_relative(f, resJitVal, 0, tgtLen); |
| |
| // If the length to copy is zero, bail out |
| jit_insn_branch_if_not(f, subLenVal, &doneLabel); |
| |
| // Set up the target string, without asking for the length. |
| genStringSetup(f, &resJitVal, res, FALSE /* pad */, FALSE /*len*/); |
| |
| jit_insn_store(f, tRes, resJitVal); |
| genUnalignedMemcpy(f, tRes, src1JitVal, subLenVal); |
| } |
| else { |
| // Do compile-time checks here, and then generate copy to completion |
| Int32 maxLen = src1->getLen(); |
| if (startPos > maxLen) |
| totalLen = 0; |
| else { |
| totalLen = (maxLen - startPos + 1); |
| if (forLen) { |
| if (forLen < totalLen) |
| totalLen = forLen; |
| } |
| } |
| |
| // Store the vc indicator length |
| tgtLen = jit_value_create_nint_constant(f,jit_type_ushort,totalLen); |
| if (res->getVcIndicatorLen() == 4) { |
| tgtLen = |
| jit_value_create_nint_constant(f, jit_type_uint, totalLen); |
| } |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| jit_insn_store_relative(f, resJitVal, 0, tgtLen); |
| |
| // Nothing to write out after length if length itself is 0. |
| if (totalLen > 0) |
| { |
| // Set up the target string, without asking for the length. |
| genStringSetup(f, &resJitVal, res, FALSE /*pad*/, FALSE /*len*/); |
| |
| tgtLen = jit_value_create_nint_constant(f,jit_type_uint,totalLen); |
| |
| jit_insn_store(f, loopIndex, tgtLen); |
| jit_insn_store(f, tRes, resJitVal); |
| genUnalignedMemcpy(f, tRes, src1JitVal, loopIndex); |
| } |
| } |
| |
| // Done! resJitVal already attached to result, so just break. |
| jit_insn_label(f, &doneLabel); |
| |
| break; |
| } |
| #endif |
| |
| case PCIT::CONCAT_MATTR5_MATTR5_MATTR5: |
| { |
| jit_value_t len1, len2, totalLen; |
| |
| // Get operands |
| src1 = inst->getROps()[0]; |
| src2 = inst->getROps()[1]; |
| res = inst->getWOps()[0]; |
| |
| // Check previously made check that src1->len + src2->len <= tgt->len |
| assert((src1->getVcMaxLen() + src2->getVcMaxLen() <= |
| res->getVcMaxLen())); |
| |
| // Set up src1 string and length |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| len1 = genStringSetup(f, &src1JitVal, src1); |
| |
| // Set up src2 string and length |
| src2JitVal = src2->getJitValue(this, f, src2->getJitType(), block); |
| len2 = genStringSetup(f, &src2JitVal, src2); |
| |
| // Calculate what the final length should be for target. |
| totalLen = jit_insn_add(f, len1, len2); |
| |
| // Get result string. Store length (if varchar) first before setting |
| // the string up. The result length does not need to be retrieved. |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| if (res->isVarchar()) { |
| if (res->getVcIndicatorLen() == 2) |
| totalLen = jit_insn_convert(f, totalLen, jit_type_ushort, 0); |
| else |
| totalLen = jit_insn_convert(f, totalLen, jit_type_uint, 0); |
| |
| jit_insn_store_relative(f, resJitVal, 0, totalLen); |
| } |
| genStringSetup(f, &resJitVal, res, FALSE /* pad */, FALSE /* len */); |
| |
| // If all operands are fixed strings, then call genUnalignedMemcpy |
| // such that the moves are inlined. |
| if (!res->isVarchar() && !src1->isVarchar() && !src2->isVarchar()) { |
| genUnalignedMemcpy(f, resJitVal, src1JitVal, NULL, src1->getLen()); |
| resJitVal = jit_insn_add(f, resJitVal, len1); |
| genUnalignedMemcpy(f, resJitVal, src2JitVal, NULL, src2->getLen()); |
| } |
| else { |
| // Call genUnalignedMemcpy such that a loop is generated to perform |
| // each of the moves. |
| jit_insn_store(f, tRes, resJitVal); |
| jit_insn_store(f, tSrc1, src1JitVal); |
| |
| // If src1 is not a varchar, length must be stored in variable first |
| if (src1->isVarchar()) |
| genUnalignedMemcpy(f, tRes, tSrc1, len1); |
| else { |
| jit_insn_store(f, loopIndex, len1); |
| genUnalignedMemcpy(f, tRes, tSrc1, loopIndex); |
| } |
| |
| // Set up next source string. Note, tRes will already be in pos |
| // for storage. |
| jit_insn_store(f, tSrc1, src2JitVal); |
| |
| // If src2 is not a varchar, length must be stored in variable first |
| if (src2->isVarchar()) |
| genUnalignedMemcpy(f, tRes, tSrc1, len2); |
| else { |
| jit_insn_store(f, loopIndex, len2); |
| genUnalignedMemcpy(f, tRes, tSrc1, loopIndex); |
| } |
| } |
| |
| // Nothing more to be done - resJitVal already attached to result. |
| |
| break; |
| } |
| |
| case PCIT::GENFUNC_MATTR5_MATTR5_IBIN32S: |
| { |
| jit_value_t len, cmp, addVal, minVal, maxVal, changeVal, b1; |
| jit_value_t temp1, temp2, temp3; |
| jit_label_t loopLabel = jit_label_undefined; |
| jit_label_t endLabel = jit_label_undefined; |
| jit_label_t noChangeLabel = jit_label_undefined; |
| Int32 subOpc = inst->code[11]; |
| |
| src1 = inst->getROps()[0]; |
| res = inst->getWOps()[0]; |
| |
| src1JitVal = src1->getJitValue(this, f, src1->getJitType(), block); |
| len = genStringSetup(f, &src1JitVal, src1); |
| |
| // Get result string. Store length (if varchar) first before setting |
| // the string up. |
| resJitVal = res->getJitValue(this, f, res->getJitType(), block); |
| if (res->isVarchar()) { |
| jit_value_t newLen; |
| if (res->getVcIndicatorLen() == 2) |
| newLen = jit_insn_convert(f, len, jit_type_ushort, 0); |
| else |
| newLen = jit_insn_convert(f, len, jit_type_uint, 0); |
| |
| jit_insn_store_relative(f, resJitVal, 0, newLen); |
| } |
| genStringSetup(f, &resJitVal, res, FALSE /* pad */, FALSE /* len */); |
| |
| if (subOpc == ITM_UPPER) { |
| minVal = jit_value_create_nint_constant(f, jit_type_sbyte, 'a'); |
| maxVal = jit_value_create_nint_constant(f, jit_type_sbyte, 'z'); |
| changeVal = jit_value_create_nint_constant(f, jit_type_sbyte, -32); |
| } else { |
| minVal = jit_value_create_nint_constant(f, jit_type_sbyte, 'A'); |
| maxVal = jit_value_create_nint_constant(f, jit_type_sbyte, 'Z'); |
| changeVal = jit_value_create_nint_constant(f, jit_type_sbyte, 32); |
| } |
| |
| // Set up pointers to be used and modified inside of loop. |
| jit_insn_store(f, tRes, resJitVal); |
| jit_insn_store(f, tSrc1, src1JitVal); |
| jit_insn_store(f, loopIndex, len); |
| |
| // Branch away if we're at end of string |
| jit_insn_branch_if_not(f, loopIndex, &endLabel); |
| |
| // Loop start |
| jit_insn_label(f, &loopLabel); |
| |
| // Get byte in source string to compare and inc/dec (if needed) |
| b1 = jit_insn_load_relative(f, tSrc1, 0, jit_type_sbyte); |
| |
| // Perform comparison(s) and branch. For eq/ne we just do one |
| cmp = jit_insn_lt(f, b1, minVal); |
| jit_insn_branch_if(f, cmp, &noChangeLabel); |
| cmp = jit_insn_gt(f, b1, maxVal); |
| jit_insn_branch_if(f, cmp, &noChangeLabel); |
| |
| // Transform byte to upper/lower case and re-save. |
| addVal = jit_insn_add(f, b1, changeVal); |
| jit_insn_store(f, b1, addVal); |
| |
| // Store byte into result. |
| jit_insn_label(f, &noChangeLabel); |
| jit_insn_store_relative(f, tRes, 0, b1); |
| |
| // Decrement loop index |
| temp1 = jit_insn_sub(f, loopIndex, oneJitVal_); |
| jit_insn_store(f, loopIndex, temp1); |
| |
| // Increment string pointers |
| temp2 = jit_insn_add(f, tSrc1, oneJitVal_); |
| temp3 = jit_insn_add(f, tRes, oneJitVal_); |
| jit_insn_store(f, tSrc1, temp2); |
| jit_insn_store(f, tRes, temp3); |
| |
| // Branch back if loop index <> 0 |
| jit_insn_branch_if(f, loopIndex, &loopLabel); |
| |
| // Nothing more to do since result written inside loop. |
| jit_insn_label(f, &endLabel); |
| |
| break; |
| } |
| } |
| } ENDFE_INST_IN_BLOCK |
| } |
| |
| // Lastly, emit an error label where we return ex_expr::ERROR, if such a |
| // label was generated. |
| if (errorJitLabel != jit_label_undefined) { |
| jit_insn_label(f, &errorJitLabel); |
| |
| // Set up arguments and make indirect call to compare routine. |
| jit_value_t atp1JitVal = jit_value_get_param(f,1); |
| jit_value_t args[2] = {atp1JitVal, exprJitVal}; |
| resJitVal = jit_insn_call_indirect(f, reportErrJitVal, |
| reportErrSig, args, 2, 0); |
| jit_insn_return(f, resJitVal); |
| } |
| |
| if (getJitFailureSeen()) { |
| jit_context_destroy(context); |
| return; |
| } |
| |
| if (debug) |
| printBlocks("NativeExpr", FALSE); |
| |
| // Set optimization level for jit compilation. |
| if (!lowerOptLevel) |
| jit_function_set_optimization_level(f, 2); |
| |
| // Dump IL for function |
| if (debug) |
| jit_dump_function(stdout, f, "IL:"); |
| |
| // Compile the function |
| Int32 size = jit_function_compile(f); |
| |
| // Get entry point into function and add code into constants array |
| ex_expr::evalPtrType entry = (ex_expr::evalPtrType)jit_function_to_closure(f); |
| CollIndex* offPtr = addConstant((void*)entry, size, 8); |
| |
| // Dump function |
| if (debug) |
| jit_dump_function(stdout, f, "X86:"); |
| |
| // Store offset into evalPtr_ |
| expr_->setEvalPtr((ex_expr::evalPtrType)(*offPtr)); |
| |
| // Mark this expression appropriately so that the native function gets called |
| expr_->setPCodeMoveFastpath(TRUE); |
| expr_->setPCodeNative(TRUE); |
| |
| if (showplanSpace) |
| { |
| NABoolean firstTimeSeen = TRUE; |
| char line[256]; |
| char* linePtr; |
| char fileName[50]; |
| Int32 i; |
| |
| // Indicates how much to indent each line. |
| const int INDENT_START = 4; |
| |
| // Filename for use in dumping text should have process pid in it. |
| sprintf(fileName, "/tmp/%d%s", getpid(), "dump1.txt"); |
| |
| // Use the jit's dump interface to generate the x86 instructions. |
| FILE* out = fopen(fileName, "w"); |
| jit_dump_function(out, f, "eval:"); |
| fclose(out); |
| |
| // First print out a header for the native expr dump |
| sprintf(line, "Native Expr (Length: %d, Opt: %d)", *offPtr, optLevel); |
| showplanSpace->allocateAndCopyToAlignedSpace(line, str_len(line), |
| sizeof(short)); |
| |
| // Start each line with some indentation. |
| for (i=0; i < INDENT_START; i++) |
| line[i] = ' '; |
| |
| // Now read from the jit dump file and feed the lines into our space |
| // object. Is there a better way of doing all of this? |
| out = fopen(fileName, "r"); |
| while (fgets(&(line[INDENT_START]), sizeof line, out) != NULL) { |
| // All lines we're interested in begin with "f", as in the address |
| // starting as "fffff..". |
| if (line[INDENT_START] != 'f') |
| continue; |
| |
| if (firstTimeSeen) { |
| // The first string is just a header that starts the dump off - we can |
| // ignore this. |
| firstTimeSeen = FALSE; |
| continue; |
| } |
| |
| // Remove newline char (if exists) since call to insert into space object |
| // automatically puts in a newline character. |
| Int32 len = str_len(line); |
| if ((len >= 1) && (line[len-1] = '\n')) { |
| len--; |
| line[len] = 0; |
| } |
| |
| showplanSpace->allocateAndCopyToAlignedSpace(line, len, sizeof(short)); |
| } |
| |
| // Close the file out and remove temporary file created. |
| fclose(out); |
| sprintf(line, "rm %s", fileName); |
| system(line); |
| |
| // Add a newline to start the next expression off cleanly. |
| showplanSpace->allocateAndCopyToAlignedSpace("\n", 1, sizeof(short)); |
| } |
| |
| // Destroy context and cleanup |
| jit_context_destroy(context); |
| } |
| #endif /* NA_LINUX_LIBJIT */ |
| |