blob: 18c5feb49064c5288973dbb102d7de306de22ddd [file] [log] [blame]
/**********************************************************************
// @@@ 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 @@@
**********************************************************************/
#include "exp_ovfl_ptal.h"
#include "exp_ieee.h"
#include "BigNumHelper.h"
#include "ExpPCodeOptimizations.h"
//
// Perform constant propogation across all blocks.
//
NABoolean PCodeCfg::constantPropagation(NABoolean doPeeling)
{
NABoolean notAllVisited, restart=FALSE;
CollIndex i;
// Mark all blocks as unvisited
clearVisitedFlags();
// Algorithm:
//
// Visit each block after all predecesors of that block have been visited.
// For each block, merge constants from all pred blocks coming into the block.
//
do
{
notAllVisited = FALSE;
FOREACH_BLOCK_REV_DFO(block, firstInst, lastInst, index)
{
// If the block has already been processed, continue to the next block.
if (block->getVisitedFlag())
continue;
const BLOCKLIST& preds = block->getPreds();
// The constant propagation algorithm could result in dead blocks. If
// we process those dead blocks, it could result in incorrect propagation
// information.
if ((preds.entries() == 0) && (block != entryBlock_)) {
deleteBlock(block);
continue;
}
// Declare constant vectors used for this block.
NABitVector zeroes(heap_), ones(heap_), neg1(heap_);
// Visit each predecessor and merge in their constants.
for (i=0; i < preds.entries(); i++)
{
if (preds[i]->getVisitedFlag() == FALSE) {
notAllVisited = TRUE;
break;
}
// Declare temp constant vectors used for merging purposes.
NABitVector tempZeroes(heap_), tempOnes(heap_), tempNeg1(heap_);
// Initialize the temp vectors with the predecessor's constant vectors.
tempZeroes = preds[i]->zeroesVector;
tempOnes = preds[i]->onesVector;
tempNeg1 = preds[i]->neg1Vector;
// Set implicit constants derived from knowing which target a branch
// took.
preds[i]->fixupConstantVectors(block, tempZeroes, tempOnes, tempNeg1);
// If this is the first pred, initialize the block's constant vectors
// to that of the preds.
if (i == 0) {
zeroes = tempZeroes;
ones = tempOnes;
neg1 = tempNeg1;
continue;
}
// Merge the preds constants into that of this blocks.
PCodeConstants::mergeConstantVectors(zeroes, ones, neg1,
tempZeroes, tempOnes, tempNeg1);
}
// Bail out if not all preds are ready..
if (i != preds.entries())
continue;
// If this is the entry block, initialize this block's constant vectors
// with the known constant's vectors of the cfg.
if (block == entryBlock_) {
zeroes += *zeroes_;
ones += *ones_;
neg1 += *neg1_;
}
restart = localConstantPropagation(block, zeroes, ones, neg1) || restart;
block->setVisitedFlag(TRUE);
// Set the block's constant vectors to the local ones used here.
block->zeroesVector = zeroes;
block->onesVector = ones;
block->neg1Vector = neg1;
if (doPeeling && block->doesBlockQualifyForShortCircuit()) {
PCodeBlock *t1, *t2;
CollIndex entries = zeroes.entries();
#if 0
CollIndex j;
printf("Block %d:\n", block->getBlockNum());
printf(" Zeroes: ");
j = zeroes.getLastStaleBit();
for (; (j = zeroes.prevUsed(j)) != NULL_COLL_INDEX; j--)
{
PCodeOperand* operand = getMap()->getFirstValue(&j);
operand->print();
printf ("(%d) ", j);
}
printf("\n");
printf(" Ones: ");
j = ones.getLastStaleBit();
for (; (j = ones.prevUsed(j)) != NULL_COLL_INDEX; j--)
{
PCodeOperand* operand = getMap()->getFirstValue(&j);
operand->print();
printf ("(%d) ", j);
}
printf("\n");
printf(" Neg1: ");
j = neg1.getLastStaleBit();
for (; (j = neg1.prevUsed(j)) != NULL_COLL_INDEX; j--)
{
PCodeOperand* operand = getMap()->getFirstValue(&j);
operand->print();
printf ("(%d) ", j);
}
printf("\n");
#endif
t1 = shortCircuitOptForBlock(block, TRUE, TRUE, zeroes, ones, neg1);
assert (zeroes.entries() == entries);
// If peeled block was generated, mark visited flag since known
// constants were updated (and set) in target block.
if (t1)
t1->setVisitedFlag(TRUE);
t2 = shortCircuitOptForBlock(block, FALSE, TRUE, zeroes, ones, neg1);
// If peeled block was generated, mark visited flag since known
// constants were updated (and set) in target block.
if (t2)
t2->setVisitedFlag(TRUE);
assert (zeroes.entries() == entries);
restart = restart || (t1 != NULL) || (t2 != NULL);
}
} ENDFE_BLOCK_REV_DFO
} while (notAllVisited);
return restart;
}
NABoolean PCodeCfg::localConstantPropagation(PCodeBlock* block,
NABitVector& zeroes,
NABitVector& ones,
NABitVector& neg1)
{
CollIndex i;
PCodeOperand *operand1, *operand2;
CollIndex bvIndex1, bvIndex2;
PCodeInst* returnInst = NULL;
Int32 returnValue = PCodeConstants::UNKNOWN_CONSTANT;
Int32 constant, constant2;
NABoolean isZero, isOne, isNeg1;
NABoolean graphChanged = FALSE;
// Use zeroes, ones, and neg1 to start constant propagating and optimizing
// this basic block
FOREACH_INST_IN_BLOCK(block, inst)
{
PCIT::Instruction opc = (PCIT::Instruction) inst->getOpcode();
PCodeBinary* code = inst->code;
NABoolean restart = TRUE;
switch (inst->getOpcode()) {
case PCIT::MOVE_MBIN16U_IBIN16U:
case PCIT::MOVE_MBIN32S_IBIN32S:
case PCIT::MOVE_MBIN8_MBIN8:
case PCIT::MOVE_MBIN16U_MBIN16U:
case PCIT::MOVE_MBIN32U_MBIN32U:
case PCIT::MOVE_MBIN64S_MBIN64S:
// These cases actually use const info regarding the write operands
// in order to optimize. Let them clear out the write operands
// themselves.
break;
default:
{
// Clear out constant assumptions for all writes
for (i=0; i < inst->getWOps().entries(); i++) {
CollIndex bvIndex = inst->getWOps()[i]->getBvIndex();
#if 0
// TODO: May need to fix this so that source operands not cleared
// as well
for (j=0; j < inst->getROps().entries(); j++) {
if ((bvIndex == inst->getROps()[j]->getBvIndex()) &&
(PCodeConstants::getConstantValue(bvIndex, zeroes, ones, neg1) !=
PCodeConstants::UNKNOWN_CONSTANT))
assert(FALSE);
}
#endif
// Special logical branches are created for the purposes of predicate
// reordering. Ignore these cases.
if (inst->isLogicalBranch())
if (bvIndex == inst->getROps()[0]->getBvIndex())
continue;
PCodeConstants::clearConstantVectors(bvIndex, zeroes, ones, neg1);
}
}
}
switch (opc)
{
case PCIT::MOVE_MBIN16U_IBIN16U:
case PCIT::MOVE_MBIN32S_IBIN32S:
{
operand1 = inst->getWOps()[0];
bvIndex1 = operand1->getBvIndex();
constant = inst->code[3];
constant2 = PCodeConstants::getConstantValue(bvIndex1, zeroes,
ones, neg1);
// Delete moves whose constants are already known.
if ((constant2 != PCodeConstants::UNKNOWN_CONSTANT) &&
(constant == constant2))
{
block->deleteInst(inst);
break;
}
// Clear out vector first since it's not done initially before switch
PCodeConstants::clearConstantVectors(bvIndex1, zeroes, ones, neg1);
PCodeConstants::setConstantInVectors(constant, bvIndex1,
zeroes, ones, neg1);
// Use constant operand instead for potential copy prop
if (constant == 0) {
PCodeInst* mv;
if (opc == PCIT::MOVE_MBIN16U_IBIN16U)
mv = block->insertNewInstAfter(inst, PCIT::MOVE_MBIN16U_MBIN16U);
else
mv = block->insertNewInstAfter(inst, PCIT::MOVE_MBIN32U_MBIN32U);
mv->code[1] = inst->code[1];
mv->code[2] = inst->code[2];
mv->code[3] = 1;
mv->code[4] = zeroOffset_;
mv->reloadOperands(this);
// Don't need the old NULL instruction any more.
block->deleteInst(inst);
}
break;
}
case PCIT::NULL_VIOLATION_MBIN16U:
operand1 = inst->getROps()[0];
zeroes += operand1->getBvIndex();
break;
case PCIT::NULL_VIOLATION_MPTR32_MPTR32_IPTR_IPTR:
case PCIT::NULL_VIOLATION_MBIN16U_MBIN16U:
{
operand1 = inst->getROps()[0];
zeroes += operand1->getBvIndex();
if ((opc != PCIT::NULL_VIOLATION_MPTR32_MPTR32_IPTR_IPTR) ||
(GetPCodeBinaryAsPtr(inst->code, 5 + PCODEBINARIES_PER_PTR) != 0))
{
operand2 = inst->getROps()[1];
zeroes += operand2->getBvIndex();
}
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:
{
bvIndex2 = inst->getROps()[0]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2,zeroes,ones,neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
inst->code[0] = (inst->getWOps()[0]->getLen() == 2)
? PCIT::MOVE_MBIN16U_MBIN16U
: PCIT::MOVE_MBIN32U_MBIN32U;
if (constant == 0) {
inst->code[3] = inst->code[6];
inst->code[4] = inst->code[7];
}
else {
inst->code[3] = inst->code[8];
inst->code[4] = inst->code[9];
}
inst->reloadOperands(this);
// For some reason the src types are MASCII - change it.
if (inst->code[0] == PCIT::MOVE_MBIN16U_MBIN16U) {
inst->getWOps()[0]->setType(PCIT::MBIN16U);
inst->getROps()[0]->setType(PCIT::MBIN16U);
}
else {
inst->getWOps()[0]->setType(PCIT::MBIN32U);
inst->getROps()[0]->setType(PCIT::MBIN32U);
}
RESTART_INST_IN_BLOCK;
}
break;
}
case PCIT::NULL_MBIN16U:
{
PCodeInst* mv;
// Propagate the known zero constant
bvIndex1 = inst->getWOps()[0]->getBvIndex();
PCodeConstants::setConstantInVectors(0, bvIndex1, zeroes, ones, neg1);
// Convert NULL into MOVE of the zero constant - good for copy prop
mv = block->insertNewInstBefore(inst, PCIT::MOVE_MBIN16U_MBIN16U);
mv->code[1] = inst->code[1];
mv->code[2] = inst->code[2];
mv->code[3] = 1;
mv->code[4] = zeroOffset_;
mv->reloadOperands(this);
// Don't need the old NULL instruction any more.
block->deleteInst(inst);
break;
}
case PCIT::NULL_BITMAP:
bvIndex1 = inst->getWOps()[0]->getBvIndex();
if (inst->code[3] == PCIT::NULL_BITMAP_SET) {
constant = (inst->code[5]) ? -1 : 0;
PCodeConstants::setConstantInVectors(constant, bvIndex1,
zeroes, ones, neg1);
}
break;
case PCIT::MOVE_MBIN32S:
bvIndex1 = inst->getROps()[0]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex1,zeroes,ones,neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
returnInst = inst;
returnValue = constant;
}
break;
case PCIT::RETURN:
if (returnInst) {
PCodeInst* ret;
ret = block->insertNewInstBefore(inst, PCIT::RETURN_IBIN32S);
ret->code[1] = returnValue;
block->deleteInst(returnInst);
block->deleteInst(inst);
}
break;
case PCIT::MOVE_MBIN8_MBIN8_IBIN32S:
{
operand1 = inst->getROps()[0];
switch (operand1->getLen()) {
case 1:
inst->code[0] = PCIT::MOVE_MBIN8_MBIN8;
break;
case 2:
inst->code[0] = PCIT::MOVE_MBIN16U_MBIN16U;
break;
case 4:
inst->code[0] = PCIT::MOVE_MBIN32U_MBIN32U;
break;
case 8:
inst->code[0] = PCIT::MOVE_MBIN64S_MBIN64S;
break;
}
if (inst->code[0] != PCIT::MOVE_MBIN8_MBIN8_IBIN32S) {
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
}
else {
// Just propagate the constants over
operand2 = inst->getWOps()[0];
PCodeConstants::copyConstantVectors(operand1->getBvIndex(),
operand2->getBvIndex(),
zeroes, ones, neg1);
}
break;
}
case PCIT::MOVE_MBIN8_MBIN8:
case PCIT::MOVE_MBIN16U_MBIN16U:
case PCIT::MOVE_MBIN32U_MBIN32U:
case PCIT::MOVE_MBIN64S_MBIN64S:
{
operand1 = inst->getROps()[0];
operand2 = inst->getWOps()[0];
bvIndex1 = operand1->getBvIndex();
bvIndex2 = operand2->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2, zeroes,
ones, neg1);
// Delete moves whose constants are already known.
if ((constant != PCodeConstants::UNKNOWN_CONSTANT) &&
(constant ==
PCodeConstants::getConstantValue(bvIndex1, zeroes, ones, neg1)))
{
block->deleteInst(inst);
break;
}
// Clear out vector first since it's not done initially before switch
PCodeConstants::clearConstantVectors(bvIndex2, zeroes, ones, neg1);
constant = PCodeConstants::copyConstantVectors(bvIndex1, bvIndex2,
zeroes, ones, neg1);
// Let peephole take care of the rest of this. This will allow copy
// propagation to proceed, which may be better.
if (operand1->isConst())
break;
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
// If constant is zero, use the constant operand in order to try and
// promote copy propagation later on
if (constant == 0) {
inst->code[3] = 1;
inst->code[4] = zeroOffset_;
inst->reloadOperands(this);
}
else {
switch (opc) {
case PCIT::MOVE_MBIN16U_MBIN16U:
inst->code[0] = PCIT::MOVE_MBIN16U_IBIN16U;
break;
case PCIT::MOVE_MBIN32U_MBIN32U:
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
break;
case PCIT::MOVE_MBIN8_MBIN8:
case PCIT::MOVE_MBIN64S_MBIN64S:
// TODO: No IBIN equivalent yet
break;
}
// If the opcode changed, update operands
if (opc != inst->code[0]) {
inst->code[3] = constant;
inst->getROps().clear();
}
}
}
break;
}
case PCIT::OR_MBIN32S_MBIN32S_MBIN32S:
#if 0
// First take advantage of the fact that all source operands into
// logical boolean operators can *AND SHOULD* only have values 0, 1,
// or -1. Therefore set this up first. Note, we don't do this if we
// know more about the operand's values than this fact alone.
for (i=0; i < 2; i++) {
operand1 = inst->getROps()[i];
bvIndex1 = operand1->getBvIndex();
// If this value truly is unknown, set it to what we do know.
if (!PCodeConstants::isAnyKnownConstants(bvIndex1,zeroes,ones,neg1)) {
zeroes += bvIndex1;
ones += bvIndex1;
neg1 += bvIndex1;
}
}
#endif
for (i=0; i < 2; i++)
{
operand1 = inst->getROps()[i];
operand2 = inst->getROps()[(i+1)%2];
bvIndex1 = operand1->getBvIndex();
bvIndex2 = operand2->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex1, zeroes,
ones, neg1);
if (constant == 1) {
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = constant;
inst->getROps().clear();
RESTART_INST_IN_BLOCK;
break;
}
if (constant == 0)
{
inst->code[0] = PCIT::MOVE_MBIN32U_MBIN32U;
inst->code[3] = operand2->getStackIndex();
inst->code[4] = operand2->getOffset();
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
if (constant == -1) {
if (PCodeConstants::isAnyKnownConstant(bvIndex2, zeroes,
ones, neg1) &&
!PCodeConstants::canBeOne(bvIndex2, ones))
{
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = -1;
inst->getROps().clear();
RESTART_INST_IN_BLOCK;
break;
}
}
}
// If no change was made above, see if we can fine tune what the known
// values of the target operand should be.
if (inst->code[0] == PCIT::OR_MBIN32S_MBIN32S_MBIN32S) {
bvIndex2 = inst->getWOps()[0]->getBvIndex();
for (i=0; i < 2; i++) {
bvIndex1 = inst->getROps()[i]->getBvIndex();
// If src is 1 or -1, result is also 1 or -1
if (PCodeConstants::isAnyKnownConstant(bvIndex1,zeroes,ones,neg1)&&
!PCodeConstants::canBeZero(bvIndex1, zeroes))
{
ones += bvIndex2;
neg1 += bvIndex2;
break;
}
}
}
break;
case PCIT::AND_MBIN32S_MBIN32S_MBIN32S:
#if 0
// First take advantage of the fact that all source operands into
// logical boolean operators can *AND SHOULD* only have values 0, 1,
// or -1. Therefore set this up first. Note, we don't do this if we
// know more about the operand's values than this fact alone.
for (i=0; i < 2; i++) {
operand1 = inst->getROps()[i];
bvIndex1 = operand1->getBvIndex();
// If this value truly is unknown, set it to what we do know.
if (!PCodeConstants::isAnyKnownConstants(bvIndex1,zeroes,ones,neg1)) {
zeroes += bvIndex1;
ones += bvIndex1;
neg1 += bvIndex1;
}
}
#endif
for (i=0; i < 2; i++)
{
operand1 = inst->getROps()[i];
operand2 = inst->getROps()[(i+1)%2];
bvIndex1 = operand1->getBvIndex();
bvIndex2 = operand2->getBvIndex();
isZero = zeroes.testBit(bvIndex1);
isOne = ones.testBit(bvIndex1);
isNeg1 = neg1.testBit(bvIndex1);
if (isZero && !isOne && !isNeg1) {
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = 0;
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
// If this operand has a value of one, and the second operand is
// known to have a value of 0, 1, or -1, result is the second
// operand. Similarly, if this operand is -1 and the second
// operand has value 0 or -1, then follow suit.
if (((isOne && !isZero && !isNeg1) &&
(zeroes.testBit(bvIndex2) || ones.testBit(bvIndex2) ||
neg1.testBit(bvIndex2)))
||
((isNeg1 && !isZero && !isOne) &&
(zeroes.testBit(bvIndex2) && neg1.testBit(bvIndex2) &&
!ones.testBit(bvIndex2))))
{
inst->code[0] = PCIT::MOVE_MBIN32U_MBIN32U;
inst->code[3] = operand2->getStackIndex();
inst->code[4] = operand2->getOffset();
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
// If this operand is -1, and the second operand is either -1
// or one, the result is -1
if ((isNeg1 && !isZero && !isOne) &&
((neg1.testBit(bvIndex2) || (ones.testBit(bvIndex2))) &&
!zeroes.testBit(bvIndex2)))
{
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = -1;
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
}
// If no change was made above, see if we can fine tune what the known
// values of the target operand should be.
if (inst->code[0] == PCIT::AND_MBIN32S_MBIN32S_MBIN32S) {
bvIndex2 = inst->getWOps()[0]->getBvIndex();
for (i=0; i < 2; i++) {
bvIndex1 = inst->getROps()[i]->getBvIndex();
// If src is 0 or -1, result is also 0 or -1
if (PCodeConstants::isAnyKnownConstant(bvIndex1,zeroes,ones,neg1)&&
!PCodeConstants::canBeOne(bvIndex1, ones))
{
zeroes += bvIndex2;
neg1 += bvIndex2;
break;
}
}
}
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:
case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MFLT64_MFLT64:
case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIGS_MBIGS_IBIN32S:
{
// Look for the null indicator used in this PCODE instruction and
// see if we know it to be NULL. If so, then this instruction
// doesn't get invoked, and therefore we can remove it.
for (i=0; i < inst->getROps().entries(); i++) {
if (((inst->getROps()[i]->getStackIndexPos() == 2) &&
(inst->getROps()[i]->getOffsetPos() == 3)) ||
((inst->getROps()[i]->getStackIndexPos() == 3) &&
(inst->getROps()[i]->getOffsetPos() == 4)))
{
bvIndex1 = inst->getROps()[i]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex1,
zeroes,ones,neg1);
if (constant == -1)
block->deleteInst(inst);
break;
}
}
break;
}
case PCIT::CLAUSE_EVAL:
{
ex_clause* clause = (ex_clause*)*(Long*)&(inst->code[1]);
if ((clause->getType() == ex_clause::FUNCTION_TYPE) &&
(clause->getClassID() == ex_clause::FUNC_RAISE_ERROR_ID) &&
(((ExpRaiseErrorFunction*)clause)->raiseError()))
{
// Create a RETURN instruction after the clause, and then fix
// up the block so as to remove trailing instrs in the block,
// *IF* a RETURN isn't already there.
if (!inst->next || !(inst->next->getOpcode() == PCIT::RETURN)) {
inst = block->insertNewInstAfter(inst, PCIT::RETURN);
block->setLastInst(inst);
inst->next = NULL;
while (block->getSuccs().entries())
block->removeEdge(block->getSuccs()[0]);
RESTART_INST_IN_BLOCK;
}
}
if (clause->getClassID() == ex_clause::AGGR_MIN_MAX_ID) {
// Get the previous opdata. It represents the condition for
// which the min/max will be performed or not. If not, then the
// entire CLAUSE_EVAL sequence can be deleted.
PCodeInst* opComp = inst->prev;
bvIndex2 = opComp->getROps()[0]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2, zeroes,
ones, neg1);
if (constant == 0) {
// Delete clause-eval instruction
block->deleteInst(inst);
}
}
break;
}
case PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S:
case PCIT::OPDATA_MPTR32_IBIN32S:
case PCIT::OPDATA_MBIN16U_IBIN32S:
case PCIT::OPDATA_MATTR5_IBIN32S:
if (inst->getWOps().entries()) {
PCodeInst* tInst = NULL;
ex_clause* clause = NULL;
// Use for identifying read operands
operand1 = NULL;
operand2 = NULL;
// Find the clause eval associated with this opdata and set
// read operands along the way.
for (tInst = inst->next;
tInst->getOpcode() != PCIT::CLAUSE_EVAL;
tInst = tInst->next)
{
if (tInst->getROps().entries()) {
if (operand1 == NULL)
operand1 = tInst->getROps()[0];
else
operand2 = tInst->getROps()[0];
}
}
assert (tInst->block == block);
// We can determine the constants of some clauses
clause = (ex_clause*)*(Long*)&(tInst->code[1]);
switch (clause->getType())
{
case ex_clause::UN_LOGIC_TYPE:
// Get read and write operands
bvIndex1 = operand1->getBvIndex();
bvIndex2 = inst->getWOps()[0]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex1, zeroes,
ones, neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
constant2 = PCodeConstants::UNKNOWN_CONSTANT;
switch (clause->getOperType()) {
case ITM_IS_UNKNOWN:
constant2 = (constant == -1) ? 1 : 0;
break;
case ITM_IS_NOT_UNKNOWN:
constant2 = (constant != -1) ? 1 : 0;
break;
case ITM_IS_TRUE:
constant2 = (constant == 1) ? 1 : 0;
break;
case ITM_IS_FALSE:
constant2 = (constant == 0) ? 1 : 0;
break;
case ITM_NOT:
if (constant == 1)
constant2 = 0;
else if (constant == 0)
constant2 = 1;
else
constant2 = -1;
break;
default:
break;
}
if (constant2 != PCodeConstants::UNKNOWN_CONSTANT) {
PCodeInst* move =
block->insertNewInstAfter(tInst,
PCIT::MOVE_MBIN32S_IBIN32S);
move->code[1] = inst->getWOps()[0]->getStackIndex();
move->code[2] = inst->getWOps()[0]->getOffset();
move->code[3] = constant2;
move->reloadOperands(this);
// Delete clause-eval instruction
block->deleteInst(tInst);
//PCodeConstants::setConstantInVectors(constant2,bvIndex2,
//zeroes, ones, neg1);
// In order to restart inst, inst needs to be assigned
// new move instruction, since inst was deleted
inst = move;
RESTART_INST_IN_BLOCK;
break;
}
}
else if (clause->getOperType() == ITM_NOT) {
if (PCodeConstants::canBeZero(bvIndex1, zeroes) &&
PCodeConstants::canBeOne(bvIndex1, ones) &&
!PCodeConstants::canBeNeg1(bvIndex1, neg1))
{
// Clause can be replaced with simple compare inst
PCodeInst* cmp =
block->insertNewInstAfter(tInst,
PCIT::EQ_MBIN32S_MBIN32S_MBIN32S);
cmp->code[1] = inst->getWOps()[0]->getStackIndex();
cmp->code[2] = inst->getWOps()[0]->getOffset();
cmp->code[3] = operand1->getStackIndex();
cmp->code[4] = operand1->getOffset();
cmp->code[5] = 1;
cmp->code[6] = zeroOffset_;
cmp->reloadOperands(this);
// Delete clause-eval instruction
block->deleteInst(tInst);
inst = cmp;
RESTART_INST_IN_BLOCK;
break;
}
else
// Result can be -1
neg1 += bvIndex2;
}
// All UN_LOGIC clauses will return 0 or 1
zeroes += bvIndex2;
ones += bvIndex2;
break;
case ex_clause::LIKE_TYPE:
case ex_clause::LIKE_CLAUSE_CHAR_ID:
case ex_clause::COMP_TYPE:
bvIndex2 = inst->getWOps()[0]->getBvIndex();
zeroes += bvIndex2;
ones += bvIndex2;
// If this clause processes nulls, we have to assume -1 can
// be returned - uggh.
if (tInst->code[1 + PCODEBINARIES_PER_PTR] & 1)
neg1 += bvIndex2;
break;
case ex_clause::BOOL_TYPE:
assert(FALSE);
break;
case ex_clause::FUNCTION_TYPE:
switch (clause->getClassID()) {
case ex_clause::FUNC_GET_BIT_VALUE_AT_ID:
bvIndex2 = inst->getWOps()[0]->getBvIndex();
zeroes += bvIndex2;
ones += bvIndex2;
break;
}
break;
}
}
break;
case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S:
// TODO: Indirect varchars are not supported right now
if (inst->code[8] == 1) {
bvIndex1 = inst->getWOps()[0]->getBvIndex();
zeroes += bvIndex1;
ones += bvIndex1;
break;
}
// Otherwise non-indirect varchar, so fall-through
case PCIT::NULL_TEST_MBIN32S_MBIN16U_IBIN32S:
{
bvIndex2= inst->getROps()[0]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2, zeroes,
ones, neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
Int32 val = 0;
switch (opc) {
case PCIT::NULL_TEST_MBIN32S_MBIN16U_IBIN32S:
val = inst->code[5];
break;
case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S:
val = inst->code[9];
break;
}
assert((val == 0) || (val == -1));
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = (constant == val) ? 1 : 0;
inst->getROps().clear();
RESTART_INST_IN_BLOCK;
break;
}
bvIndex1 = inst->getWOps()[0]->getBvIndex();
zeroes += bvIndex1;
ones += bvIndex1;
break;
}
case PCIT::ZERO_MBIN32S_MBIN32U:
case PCIT::NOTZERO_MBIN32S_MBIN32U:
case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S:
case PCIT::NE_MBIN32S_MBIN16S_MBIN16S:
case PCIT::LT_MBIN32S_MBIN16S_MBIN16S:
case PCIT::GT_MBIN32S_MBIN16S_MBIN16S:
case PCIT::LE_MBIN32S_MBIN16S_MBIN16S:
case PCIT::GE_MBIN32S_MBIN16S_MBIN16S:
case PCIT::EQ_MBIN32S_MBIN16S_MBIN32S:
case PCIT::LT_MBIN32S_MBIN16S_MBIN32S:
case PCIT::GT_MBIN32S_MBIN16S_MBIN32S:
case PCIT::LE_MBIN32S_MBIN16S_MBIN32S:
case PCIT::GE_MBIN32S_MBIN16S_MBIN32S:
case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S:
case PCIT::LT_MBIN32S_MBIN32S_MBIN32S:
case PCIT::GT_MBIN32S_MBIN32S_MBIN32S:
case PCIT::LE_MBIN32S_MBIN32S_MBIN32S:
case PCIT::GE_MBIN32S_MBIN32S_MBIN32S:
case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U:
case PCIT::LT_MBIN32S_MBIN16U_MBIN16U:
case PCIT::GT_MBIN32S_MBIN16U_MBIN16U:
case PCIT::LE_MBIN32S_MBIN16U_MBIN16U:
case PCIT::GE_MBIN32S_MBIN16U_MBIN16U:
case PCIT::EQ_MBIN32S_MBIN16U_MBIN32U:
case PCIT::LT_MBIN32S_MBIN16U_MBIN32U:
case PCIT::GT_MBIN32S_MBIN16U_MBIN32U:
case PCIT::LE_MBIN32S_MBIN16U_MBIN32U:
case PCIT::GE_MBIN32S_MBIN16U_MBIN32U:
case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U:
case PCIT::LT_MBIN32S_MBIN32U_MBIN32U:
case PCIT::GT_MBIN32S_MBIN32U_MBIN32U:
case PCIT::LE_MBIN32S_MBIN32U_MBIN32U:
case PCIT::GE_MBIN32S_MBIN32U_MBIN32U:
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:
case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S:
case PCIT::LT_MBIN32S_MBIN16U_MBIN16S:
case PCIT::GT_MBIN32S_MBIN16U_MBIN16S:
case PCIT::LE_MBIN32S_MBIN16U_MBIN16S:
case PCIT::GE_MBIN32S_MBIN16U_MBIN16S:
case PCIT::NE_MBIN32S_MBIN64S_MBIN64S:
case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S:
case PCIT::LT_MBIN32S_MBIN64S_MBIN64S:
case PCIT::GT_MBIN32S_MBIN64S_MBIN64S:
case PCIT::LE_MBIN32S_MBIN64S_MBIN64S:
case PCIT::GE_MBIN32S_MBIN64S_MBIN64S:
case PCIT::NE_MBIN32S_MASCII_MASCII:
case PCIT::EQ_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::NE_MBIN32S_MFLT64_MFLT64:
case PCIT::EQ_MBIN32S_MFLT64_MFLT64:
case PCIT::LT_MBIN32S_MFLT64_MFLT64:
case PCIT::GT_MBIN32S_MFLT64_MFLT64:
case PCIT::LE_MBIN32S_MFLT64_MFLT64:
case PCIT::GE_MBIN32S_MFLT64_MFLT64:
case PCIT::NE_MBIN32S_MFLT32_MFLT32:
case PCIT::EQ_MBIN32S_MFLT32_MFLT32:
case PCIT::LT_MBIN32S_MFLT32_MFLT32:
case PCIT::GT_MBIN32S_MFLT32_MFLT32:
case PCIT::LE_MBIN32S_MFLT32_MFLT32:
case PCIT::GE_MBIN32S_MFLT32_MFLT32:
case PCIT::COMP_MBIN32S_MUNIV_MUNIV_IBIN32S:
case PCIT::COMP_MBIN32S_MATTR5_MATTR5_IBIN32S:
case PCIT::COMP_MBIN32S_MUNI_MUNI_IBIN32S_IBIN32S_IBIN32S:
case PCIT::COMP_MBIN32S_MBIGS_MBIGS_IBIN32S_IBIN32S:
case PCIT::COMP_MBIN32S_MASCII_MASCII_IBIN32S_IBIN32S_IBIN32S:
case PCIT::LIKE_MBIN32S_MATTR5_MATTR5_IBIN32S_IBIN32S:
{
bvIndex2 = inst->getWOps()[0]->getBvIndex();
zeroes += bvIndex2;
ones += bvIndex2;
break;
}
case PCIT::SWITCH_MBIN32S_MBIN64S_MPTR32_IBIN32S_IBIN32S:
case PCIT::SWITCH_MBIN32S_MATTR5_MPTR32_IBIN32S_IBIN32S:
{
// If for IN-lists, result can only be 0 or 1.
if (inst->isInListSwitch()) {
bvIndex2 = inst->getWOps()[0]->getBvIndex();
zeroes += bvIndex2;
ones += bvIndex2;
}
break;
}
case PCIT::NNB_MBIN32S_MATTR3_IBIN32S_IBIN32S:
{
PCodeInst* mv;
PCodeBlock* fallThrough = block->getSuccs()[0];
// Add move to fall-through
mv = fallThrough->insertNewInstBefore(NULL, PCIT::MOVE_MBIN32S_IBIN32S);
mv->code[1] = inst->getWOps()[0]->getStackIndex();
mv->code[2] = inst->getWOps()[0]->getOffset();
mv->code[3] = inst->code[6];
mv->reloadOperands(this);
// Rewrite branch to not have write operand
inst->code[0] = PCIT::NNB_MATTR3_IBIN32S;
inst->code[1] = inst->getROps()[0]->getStackIndex();
inst->code[2] = inst->getROps()[0]->getOffset();
inst->code[3] = inst->getROps()[0]->getNullBitIndex();
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_IBIN32S_IBIN32S:
{
PCodeInst* mv;
PCodeBlock* fallThrough = block->getSuccs()[0];
// Add move to fall-through
mv = fallThrough->insertNewInstBefore(NULL, PCIT::MOVE_MBIN32S_IBIN32S);
mv->code[1] = inst->getWOps()[0]->getStackIndex();
mv->code[2] = inst->getWOps()[0]->getOffset();
mv->code[3] = inst->code[5];
mv->reloadOperands(this);
// Rewrite branch to not have write operand
inst->code[0] = PCIT::NOT_NULL_BRANCH_MBIN16S_IBIN32S;
inst->code[1] = inst->getROps()[0]->getStackIndex();
inst->code[2] = inst->getROps()[0]->getOffset();
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
case PCIT::NNB_MATTR3_IBIN32S:
case PCIT::NOT_NULL_BRANCH_MBIN16S_IBIN32S:
{
bvIndex1 = inst->getROps()[0]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex1, zeroes,
ones, neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
if (constant == 0) {
inst->code[0] = PCIT::BRANCH;
inst->getROps().clear();
block->removeEdge(block->getFallThroughBlock());
break;
}
else {
block->removeEdge(block->getTargetBlock());
block->deleteInst(inst);
}
graphChanged = TRUE; // CFG was modifed
}
// Otherwise we can at least propagate what we do know
zeroes += bvIndex1;
neg1 += bvIndex1;
break;
}
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S:
{
operand1 = inst->getWOps()[0];
bvIndex1 = operand1->getBvIndex();
bvIndex2 = inst->getROps()[0]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2, zeroes,
ones, neg1);
// Constants must be known, *and* target can't be indirect varchar
if (((constant == -1) || (constant == 0)) &&
(operand1->getOffset() >= 0))
{
if (!operand1->forAlignedFormat()) {
inst->code[0] = PCIT::MOVE_MBIN16U_IBIN16U;
inst->code[3] = (constant == 0) ? 0 : -1;
}
else {
inst->code[0] = PCIT::NULL_BITMAP;
inst->code[3] = PCIT::NULL_BITMAP_SET;
inst->code[4] = operand1->getNullBitIndex();
inst->code[5] = (constant == 0) ? 0 : 1;
}
if (constant == 0) {
block->insertNewInstAfter(inst, PCIT::BRANCH);
block->removeEdge(block->getFallThroughBlock());
}
else {
block->removeEdge(block->getTargetBlock());
}
graphChanged = TRUE; // CFG was modifed
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
zeroes += bvIndex1;
neg1 += bvIndex1;
break;
}
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S:
{
operand1 = inst->getWOps()[0];
constant = PCodeConstants::getConstantValue(
inst->getROps()[0]->getBvIndex(), zeroes, ones, neg1);
constant2 = PCodeConstants::getConstantValue(
inst->getROps()[1]->getBvIndex(), zeroes, ones, neg1);
NABoolean isNull = ((constant == -1) || (constant2 == -1));
NABoolean isNotNull = ((constant == 0) && (constant2 == 0));
//TODO: add case where if either constant or constant2 is 0, then
//reduce NNBB branch to shorter form.
// Constants must be known, *and* target can't be indirect varchar
if ((isNull || isNotNull) && (operand1->getOffset() >= 0))
{
if (!operand1->forAlignedFormat()) {
inst->code[0] = PCIT::MOVE_MBIN16U_IBIN16U;
inst->code[3] = (isNull) ? -1 : 0;
}
else {
inst->code[0] = PCIT::NULL_BITMAP;
inst->code[3] = PCIT::NULL_BITMAP_SET;
inst->code[4] = operand1->getNullBitIndex();
inst->code[5] = (isNull) ? 1 : 0;
}
if (isNotNull) {
block->insertNewInstAfter(inst, PCIT::BRANCH);
block->removeEdge(block->getFallThroughBlock());
}
else {
block->removeEdge(block->getTargetBlock());
}
graphChanged = TRUE; // CFG was modifed
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
else if ((constant == 0) || (constant2 == 0))
{
}
bvIndex1 = operand1->getBvIndex();
zeroes += bvIndex1;
neg1 += bvIndex1;
break;
}
case PCIT::NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S:
{
// Go through each read operand.
for (i=0; i < 2; i++) {
operand2 = inst->getROps()[i];
bvIndex2 = inst->getROps()[i]->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2, zeroes,
ones, neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
if (constant == 0) {
// Get constant of second operand
constant = PCodeConstants::getConstantValue(
inst->getROps()[(i+1)%2]->getBvIndex(),
zeroes, ones, neg1);
if (constant != 0)
continue;
// Both operands are zero
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = 0;
inst->reloadOperands(this);
block->insertNewInstAfter(inst, PCIT::BRANCH);
block->removeEdge(block->getFallThroughBlock());
}
else {
assert (constant == -1);
PCodeInst* newInst;
PCodeOperand* op = (i == 0) ? inst->getROps()[1]
: inst->getROps()[0];
newInst = block->insertNewInstBefore(inst,
PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S);
newInst->code[1] = inst->code[1];
newInst->code[2] = inst->code[2];
newInst->code[3] = op->getStackIndex();
newInst->code[4] = op->getOffset();
newInst->code[5] = -1; // voa that's unnecessary.
newInst->code[6] = (op->forAlignedFormat())
? ExpTupleDesc::SQLMX_ALIGNED_FORMAT
: ExpTupleDesc::SQLARK_EXPLODED_FORMAT;
newInst->code[7] = op->getNullBitIndex();
newInst->code[8] = 0; // No voa lookup needed.
newInst->code[9] = -1; // Test for NULL
newInst->reloadOperands(this);
block->deleteInst(inst);
inst = newInst;
// inst->code[0] = PCIT::EQ_MBIN32S_MBIN16S_MBIN16S;
block->removeEdge(block->getTargetBlock());
}
graphChanged = TRUE; // CFG was modifed
RESTART_INST_IN_BLOCK;
break;
}
}
bvIndex1 = inst->getWOps()[0]->getBvIndex();
zeroes += bvIndex1;
ones += bvIndex1;
break;
}
case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S:
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_IBIN32S:
case PCIT::NOT_NULL_BRANCH_MBIN16S_MBIN16S_IBIN32S:
{
operand1 = inst->getROps()[0];
operand2 = inst->getWOps()[0];
bvIndex1 = operand1->getBvIndex();
bvIndex2 = operand2->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex1, zeroes,
ones, neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
switch(opc) {
case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S:
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_IBIN32S:
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
break;
case PCIT::NOT_NULL_BRANCH_MBIN16S_MBIN16S_IBIN32S:
inst->code[0] = PCIT::MOVE_MBIN16U_IBIN16U;
break;
}
inst->code[1] = operand2->getStackIndex();
inst->code[2] = operand2->getOffset();
inst->code[3] = constant;
inst->reloadOperands(this);
if (constant == 0) {
block->insertNewInstAfter(inst, PCIT::BRANCH);
block->removeEdge(block->getFallThroughBlock());
}
else {
block->removeEdge(block->getTargetBlock());
}
graphChanged = TRUE; // CFG was modifed
RESTART_INST_IN_BLOCK;
continue;
}
zeroes += bvIndex1;
neg1 += bvIndex1;
zeroes += bvIndex2;
neg1 += bvIndex2;
break;
}
case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S:
operand1 = inst->getWOps()[0];
bvIndex1 = operand1->getBvIndex();
for (i=0; i < 2; i++) {
operand2 = inst->getROps()[i];
bvIndex2 = operand2->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2, zeroes,
ones, neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
inst->code[0] =
PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S;
if (constant == -1) {
inst->code[3] = operand2->getStackIndex();
inst->code[4] = operand2->getOffset();
inst->code[5] = inst->code[7];
PCodeAttrNull * newAttr = (PCodeAttrNull *)&(inst->code[5]);
PCodeAttrNull * oldAttr = (PCodeAttrNull *)&(inst->code[7]);
// New size is 3 less since we're getting rid of 1 source op,
// which is made up of index and offset, and 1 null bit index,
// which corresponds to that source.
newAttr->fmt_.size_ = oldAttr->fmt_.size_ - 3;
// If src is second operand, need to set format correctly.
// Otherwise it, along with target, are already set right.
if (i == 1)
newAttr->fmt_.op2Fmt_ = oldAttr->fmt_.op3Fmt_;
inst->code[6] = operand1->getNullBitIndex();
inst->code[7] = operand2->getNullBitIndex();
}
else {
inst->code[3] = inst->getROps()[(i+1)%2]->getStackIndex();
inst->code[4] = inst->getROps()[(i+1)%2]->getOffset();
inst->code[5] = inst->code[7];
PCodeAttrNull * newAttr = (PCodeAttrNull *)&(inst->code[5]);
PCodeAttrNull * oldAttr = (PCodeAttrNull *)&(inst->code[7]);
// New size is 2 less since we're getting rid of 1 source op
// which is made up of index and offset.
newAttr->fmt_.size_ = oldAttr->fmt_.size_ - 3;
// If src is first operand, need to get format of 2nd op
// Otherwise it, along with target, are already set right.
if (i == 0)
newAttr->fmt_.op2Fmt_ = oldAttr->fmt_.op3Fmt_;
inst->code[6] = operand1->getNullBitIndex();
inst->code[7] = inst->getROps()[(i+1)%2]->getNullBitIndex();
}
inst->reloadOperands(this);
RESTART_INST_IN_BLOCK;
break;
}
}
zeroes += bvIndex1;
neg1 += bvIndex1;
break;
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_MBIN16S_IBIN32S:
case PCIT::NOT_NULL_BRANCH_MBIN16S_MBIN16S_MBIN16S_IBIN32S:
operand1 = inst->getWOps()[0];
bvIndex1 = operand1->getBvIndex();
for (i=0; i < 2; i++) {
operand2 = inst->getROps()[i];
bvIndex2 = operand2->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex2, zeroes,
ones, neg1);
if ((constant == -1) || (constant == 0)) {
if (opc==PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_MBIN16S_IBIN32S)
inst->code[0] = PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_IBIN32S;
else
inst->code[0] = PCIT::NOT_NULL_BRANCH_MBIN16S_MBIN16S_IBIN32S;
if (constant == 0) {
inst->code[3] = inst->getROps()[(i+1)%2]->getStackIndex();
inst->code[4] = inst->getROps()[(i+1)%2]->getOffset();
}
else {
inst->code[3] = operand2->getStackIndex();
inst->code[4] = operand2->getOffset();
}
inst->code[5] = inst->code[7];
inst->reloadOperands(this);
// No need to change anything else since retrying the new
// instruction will end up removing this instruction.
RESTART_INST_IN_BLOCK;
break;
}
}
zeroes += bvIndex1;
neg1 += bvIndex1;
break;
case PCIT::NULL_BITMAP_BULK:
case PCIT::NOT_NULL_BRANCH_BULK:
for (i=0; i < inst->getROps().entries(); i++) {
bvIndex2 = inst->getROps()[i]->getBvIndex();
zeroes += bvIndex2;
neg1 += bvIndex2;
}
break;
case PCIT::BRANCH_OR:
case PCIT::BRANCH_AND:
{
operand1 = inst->getROps()[0];
operand2 = inst->getWOps()[0];
bvIndex1 = operand1->getBvIndex();
bvIndex2 = operand2->getBvIndex();
constant = PCodeConstants::getConstantValue(bvIndex1, zeroes,
ones, neg1);
if (constant != PCodeConstants::UNKNOWN_CONSTANT) {
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[1] = operand2->getStackIndex();
inst->code[2] = operand2->getOffset();
inst->code[3] = constant;
inst->reloadOperands(this);
if (((opc == PCIT::BRANCH_OR) && (constant == 1)) ||
((opc == PCIT::BRANCH_AND) && (constant == 0)))
{
block->insertNewInstAfter(inst, PCIT::BRANCH);
block->removeEdge(block->getFallThroughBlock());
}
else {
block->removeEdge(block->getTargetBlock());
}
graphChanged = TRUE; // CFG was modifed
RESTART_INST_IN_BLOCK;
break;
}
else if (block->getFallThroughBlock() == block->getTargetBlock())
{
// Don't ask me why, but sometimes we see this: executor/TEST038
// Change branch to move and fall-through
inst->code[0] = PCIT::MOVE_MBIN32U_MBIN32U;
inst->code[1] = operand2->getStackIndex();
inst->code[2] = operand2->getOffset();
inst->code[3] = operand1->getStackIndex();
inst->code[4] = operand1->getOffset();
inst->reloadOperands(this);
block->removeEdge(block->getTargetBlock());
graphChanged = TRUE; // CFG was modifed
// TODO: Restart once we add constant prop support for MOVEs
// other than constant moves.
//RESTART_INST_IN_BLOCK;
//break;
}
// The operand of a logical branch should have a boolean value. In
// our case, the values can be 0, 1, or -1. If the read operand
// is unknown, or if certain values are not possible (e.g. -1)
// then set that up first.
if (!PCodeConstants::isAnyKnownConstant(bvIndex1,zeroes,ones,neg1))
{
zeroes += bvIndex1;
ones += bvIndex1;
neg1 += bvIndex1;
}
// If a change was a made, restart without setting write constants
if (inst->getOpcode() != opc) {
RESTART_INST_IN_BLOCK;
break;
}
// Set up write constants
PCodeConstants::copyConstantVectors(bvIndex1, bvIndex2,
zeroes, ones, neg1);
//
// Sometimes a logical branch targets a logic instruction
// unnecessarily. This is a branch optimization which could be
// done in cfgRewiring(), but we opt to do it here instead. An
// example of this is:
//
// [1]
// BRANCH_AND (168) 13 0 2 8 2 12 (Tgt: 4)
// ...
// [4] (Preds: 2 )
// AND_MBIN32S_MBIN32S_MBIN32S (63) 2 8 2 12 2 16
//
// [5] (Preds: 1 )
// OR_MBIN32S_MBIN32S_MBIN32S (64) 2 0 2 4 2 8
//
// We should just be able to branch from 1 directly to 5.
//
// Target block should have a single logical instruction.
PCodeBlock* tgtBlock = block->getTargetBlock();
if (tgtBlock->getLastInst() &&
(tgtBlock->getLastInst() == tgtBlock->getFirstInst()))
{
PCodeInst* logicInst = tgtBlock->getLastInst();
Int32 subOpc = logicInst->getOpcode();
// ((BRANCH_OR -> OR) or (BRANCH_AND -> AND)) and both insts have
// the same write operand.
if ((((opc == PCIT::BRANCH_OR) &&
(subOpc == PCIT::OR_MBIN32S_MBIN32S_MBIN32S)) ||
((opc == PCIT::BRANCH_AND) &&
(subOpc == PCIT::AND_MBIN32S_MBIN32S_MBIN32S))) &&
(logicInst->getWOps()[0]->getBvIndex() ==
inst->getWOps()[0]->getBvIndex()))
{
// The read operand of the branch must be a read operand of the
// logic instruction.
CollIndex branchOpIdx = inst->getROps()[0]->getBvIndex();
if ((logicInst->getROps()[0]->getBvIndex() == branchOpIdx) ||
(logicInst->getROps()[1]->getBvIndex() == branchOpIdx))
{
// Re-target branch to fall-through of original target block.
block->removeEdge(block->getTargetBlock());
block->addEdge(tgtBlock->getFallThroughBlock());
graphChanged = TRUE; // CFG was modifed
}
}
}
break;
}
}
} ENDFE_INST_IN_BLOCK
return graphChanged;
}
//
// Change moves from constant's area to direct immediate moves.
//
void PCodeCfg::constantFolding()
{
FOREACH_BLOCK(block, firstInst, lastInst, index) {
FOREACH_INST_IN_BLOCK(block, inst) {
if (inst->isMove()) {
PCodeOperand* operand2 = inst->getROps()[0];
if (!operand2->isConst())
continue;
switch(inst->getOpcode()) {
case PCIT::MOVE_MBIN16U_MBIN8:
inst->code[0] = PCIT::MOVE_MBIN16U_IBIN16U;
inst->code[3] = (UInt8)getIntConstValue(operand2);
break;
case PCIT::MOVE_MBIN32U_MBIN16U:
case PCIT::MOVE_MBIN32S_MBIN16U:
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = (UInt16)getIntConstValue(operand2);
break;
case PCIT::MOVE_MBIN32S_MBIN16S:
case PCIT::MOVE_MBIN32U_MBIN16S:
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = (Int16)getIntConstValue(operand2);
break;
case PCIT::MOVE_MBIN16U_MBIN16U:
inst->code[0] = PCIT::MOVE_MBIN16U_IBIN16U;
inst->code[3] = (UInt16)getIntConstValue(operand2);
break;
case PCIT::MOVE_MBIN32U_MBIN32U:
inst->code[0] = PCIT::MOVE_MBIN32S_IBIN32S;
inst->code[3] = (UInt32)getIntConstValue(operand2);
break;
case PCIT::MOVE_MBIN8_MBIN8:
continue;
case PCIT::MOVE_MBIN64S_MBIN16U:
case PCIT::MOVE_MBIN64S_MBIN16S:
case PCIT::MOVE_MBIN64S_MBIN32U:
case PCIT::MOVE_MBIN64S_MBIN32S:
continue;
case PCIT::MOVE_MBIN64S_MBIN64S:
continue;
default:
continue;
}
inst->reloadOperands(this);
}
} ENDFE_INST_IN_BLOCK
} ENDFE_BLOCK
}
//
// Given an operand known to be a constant, lookup it's value as a string and
// return it (and its length via an incoming parameter).
//
char* PCodeCfg::getStringConstValue(PCodeOperand* op, Int32* len)
{
CollIndex off = op->getOffset();
if (op->isVarchar()) {
off = off - op->getVcIndicatorLen() - op->getVcNullIndicatorLen();
}
PCodeConstants* constPtr = offsetToConstMap_->getFirstValue(&off);
assert(constPtr != NULL);
switch (op->getType()) {
case PCIT::MASCII:
*len = op->getLen();
return (char*)(constPtr->getData());
case PCIT::MATTR5:
if (op->isVarchar()) {
*len = ((op->getVcIndicatorLen() == 2)
? (Int32)(*((Int16*)((char*)constPtr->getData() +
op->getVcNullIndicatorLen())))
: (Int32)(*((Int32*)((char*)constPtr->getData() +
op->getVcNullIndicatorLen()))));
return ((char*)constPtr->getData() + op->getVcIndicatorLen() +
op->getVcNullIndicatorLen());
}
// Otherwise we have a fixed-length string.
*len = op->getLen();
return (char*)(constPtr->getData());
default:
assert(FALSE);
break;
}
return NULL;
}
//
// Given any pointer operand, return the pointer to it.
//
void* PCodeCfg::getPtrConstValue(PCodeOperand* op)
{
CollIndex off = op->getOffset();
// This routine can be called before PCodeConstant objects are initialized.
// As such, the offset must come directly from the constants area of the expr.
if (offsetToConstMap_ == NULL) {
char * stk = expr_->getConstantsArea();
Int32 len = expr_->getConstsLength();
assert (off < (CollIndex)len);
return (void*)(stk + off);
}
// Otherwise constant should be recorded in constants map.
PCodeConstants* constPtr = offsetToConstMap_->getFirstValue(&off);
if (constPtr == NULL)
return NULL;
return (void*)(constPtr->getData());
}
//
// Given an operand known to be an integer, find its value and return it.
//
Int64 PCodeCfg::getIntConstValue(PCodeOperand* op)
{
CollIndex off = op->getOffset();
// TODO: move this calculation to getStringValue()
if (op->isVarchar()) {
off = off - op->getVcIndicatorLen() - op->getVcNullIndicatorLen();
}
PCodeConstants* constPtr = offsetToConstMap_->getFirstValue(&off);
//
// All integer constant operands should be found in constants hash table. If
// not, then they must be constants defined prior to optimizations. An
// example on how this can happen is a MOVE_MBIN8_MBIN8_IBIN32S which has a
// constant read operand with type MPTR32. Operands with type MPTR32 are not
// currently tracked. If this instruction is converted into a normal (known
// sized) move, then constant folding may be called and it may be further
// converted into an immediate move.
//
// TODO: Keep the assert for now (change made in ::getAlign() to recognize
// PCIT::MPTR32 operand (giving it worst-case 8-byte alignment).
//
assert(constPtr != NULL);
Int64 value = 0;
switch (op->getType()) {
case PCIT::MBIN8:
value = (Int64)*((UInt8*)(constPtr->getData()));
break;
case PCIT::MBIN8S:
value = (Int64)*((Int8*)(constPtr->getData()));
break;
case PCIT::MBIN8U:
value = (Int64)*((UInt8*)(constPtr->getData()));
break;
case PCIT::MBIN16S:
value = (Int64)*((Int16*)(constPtr->getData()));
break;
case PCIT::MBIN16U:
value = (Int64)*((UInt16*)(constPtr->getData()));
break;
case PCIT::MBIN32S:
value = (Int64)*((Int32*)(constPtr->getData()));
break;
case PCIT::MBIN32U:
value = (Int64)*((UInt32*)(constPtr->getData()));
break;
case PCIT::MBIN64S:
value = (Int64)*((Int64*)(constPtr->getData()));
break;
case PCIT::MPTR32:
switch (constPtr->getLen()) {
case 1:
value = (Int64)*((UInt8*)(constPtr->getData()));
break;
case 2:
value = (Int64)*((Int16*)(constPtr->getData()));
break;
case 4:
value = (Int64)*((Int32*)(constPtr->getData()));
break;
case 8:
value = (Int64)*((Int64*)(constPtr->getData()));
break;
default:
assert(FALSE);
}
break;
default:
assert(FALSE);
break;
}
return value;
}
//
// Given an operand known to be a float, find its value and return it.
//
double PCodeCfg::getFloatConstValue(PCodeOperand* op)
{
CollIndex off = op->getOffset();
// TODO: move this calculation to getStringValue()
if (op->isVarchar()) {
off = off - op->getVcIndicatorLen() - op->getVcNullIndicatorLen();
}
PCodeConstants* constPtr = offsetToConstMap_->getFirstValue(&off);
// All integer constant operands should be found in constants hash table.
assert(constPtr != NULL);
double value = 0;
switch (op->getType()) {
case PCIT::MFLT64:
value = *((double*)(constPtr->getData()));
break;
case PCIT::MFLT32:
value = *((float*)(constPtr->getData()));
break;
default:
assert(FALSE);
break;
}
return value;
}
//
// Add a new integer constant. The alignment param is used to indicate the
// size of the datum as well as it's alignment.
//
Int32 PCodeCfg::addNewIntConstant(Int64 value, Int32 alignment)
{
// Quickly return the zero offset if it exists and we're looking to add 0.
if ((value == 0) && (zeroOffset_ != -1))
return zeroOffset_;
switch (alignment) {
case 1:
{
UInt8 val = (UInt8)value;
return *(addConstant(&val, alignment, alignment));
}
case 2:
{
UInt16 val = (UInt16)value;
return *(addConstant(&val, alignment, alignment));
}
case 4:
{
UInt32 val = (UInt32)value;
return *(addConstant(&val, alignment, alignment));
}
case 8:
{
return *(addConstant(&value, alignment, alignment));
}
default:
assert(FALSE);
}
return -1;
}
//
// Add a new float constant. The alignment param is used to indicate the
// size of the datum as well as it's alignment.
//
Int32 PCodeCfg::addNewFloatConstant(double value, Int32 alignment)
{
switch (alignment) {
case 4:
{
float val = (float)value;
return *(addConstant(&val, alignment, alignment));
}
case 8:
{
return *(addConstant(&value, alignment, alignment));
}
default:
assert(FALSE);
}
return -1;
}
//
// Constant fold instructions with input operands known to be constant. It's
// important to update the reaching defs information if the new instruction
// being added is generated from scratch - see updateReachingDefs().
//
PCodeInst* PCodeCfg::constantFold(PCodeInst* inst, NABoolean rDefsAvailable)
{
CollIndex i;
PCodeOperand *op1, *op2;
Int16 ov; // overflow indicator
Int32 opc = inst->getOpcode();
switch (opc) {
#if 0
case PCIT::CLAUSE_EVAL:
{
ex_expr::exp_return_type retCode;
char *opData[3 * ex_clause::MAX_OPERANDS];
char **opDataData = &opData[2 * ex_clause::MAX_OPERANDS];
clause = inst->code[1];
if (inst->mustProcessNulls() ||
!inst->clauseInitOperandsForConstFold(opData, heap_))
return;
retCode = clause->eval(opDataData, heap_, diagsArea)
if (retCode == ex_expr::EXPR_ERROR)
return;
break;
}
#endif
case PCIT::MOVE_MASCII_MASCII_IBIN32S_IBIN32S:
case PCIT::MOVE_MASCII_MATTR5_IBIN32S:
{
Int32 len, tgtLen;
CollIndex* off;
// Folding inst into same-sized moves is useful for copy propagation, and
// that being only if the write operand is a temp.
if (!inst->getWOps()[0]->isTemp())
break;
op2 = inst->getROps()[0];
if (op2->isConst()) {
assert(!op2->isIndirectVarchar());
op1 = inst->getWOps()[0];
tgtLen = op1->getLen();
char* str = getStringConstValue(op2, &len);
Int32 padLen = tgtLen - len;
char* newStr = (char*)new(heap_) char[tgtLen];
if (padLen > 0) {
str_cpy_all(newStr, str, len);
str_pad(newStr + len, padLen, ' ');
}
else {
str_cpy_all(newStr, str, tgtLen);
}
off = addConstant((void*)newStr, tgtLen, 1);
inst->code[0] = PCIT::MOVE_MBIN8_MBIN8_IBIN32S;
inst->code[3] = 1;
inst->code[4] = *off;
inst->code[5] = tgtLen;
NADELETEBASIC(newStr, heap_);
inst->reloadOperands(this);
}
break;
}
case PCIT::MOVE_MATTR5_MASCII_IBIN32S:
{
Int32 len, tgtLen;
CollIndex* off;
op1 = inst->getWOps()[0];
// Folding inst into same-sized moves is useful for copy propagation, and
// that being only if the write operand is a temp.
if (!op1->isTemp())
break;
op2 = inst->getROps()[0];
if (op2->isConst()) {
// Get source string
char* str = getStringConstValue(op2, &len);
// Since char is being stored in varchar, if the length is too big to
// be represented by a varchar (in terms of a 2-byte vc length field),
// then skip this transformation.
if (len >= SHRT_MAX)
break;
// Target length that should be stored.
tgtLen = (op1->getVcMaxLen() >= len) ? len : op1->getVcMaxLen();
// Allocate new varchar string with 2 bytes for vc len
char* newStr = (char*) new(heap_) char[2 + tgtLen];
*((Int16*)(newStr)) = (Int16)tgtLen;
str_cpy_all(newStr + 2, str, tgtLen);
off = addConstant((void*)newStr, tgtLen + 2, 2);
Int32 comboLen = 0;
char* comboPtr = (char*)(&comboLen);
comboPtr[0] = 0; // no null
comboPtr[1] = 2; // vc length is 2 bytes
PCodeInst* newInst;
PCodeBlock* block = inst->block;
newInst = block->insertNewInstAfter(inst, PCIT::MOVE_MATTR5_MATTR5);
newInst->code[1] = inst->code[1];
newInst->code[2] = inst->code[2];
newInst->code[3] = inst->code[3];
newInst->code[4] = inst->code[4];
newInst->code[5] = inst->code[5];
newInst->code[6] = 1;
newInst->code[7] = *off + 2; // Up 2 to get to str itself
newInst->code[8] = -1; // voa
newInst->code[9] = op1->getVcMaxLen(); // tgt/src share max vc length
newInst->code[10] = comboLen;
newInst->reloadOperands(this);
// Attempt to update reaching defs info.
if (rDefsAvailable)
updateReachingDefs(block, op1->getBvIndex(), inst, newInst);
block->deleteInst(inst);
inst = newInst;
NADELETEBASIC(newStr, heap_);
}
break;
}
case PCIT::MOVE_MBIGS_MBIN16S_IBIN32S:
case PCIT::MOVE_MBIGS_MBIN32S_IBIN32S:
case PCIT::MOVE_MBIGS_MBIN64S_IBIN32S:
{
op1 = inst->getWOps()[0];
// Folding inst into same-sized moves is useful for copy propagation, and
// that being only if the write operand is a temp.
if (!op1->isTemp())
break;
op2 = inst->getROps()[0];
if (op2->isConst()) {
CollIndex* off;
Int64 value = getIntConstValue(op2);
Int32 tgtLen = inst->getWOps()[0]->getLen();
char* result = (char*) new(heap_) char[tgtLen];
BigNumHelper::ConvInt64ToBigNumWithSignHelper(tgtLen, value, result, FALSE);
off = addConstant((void*)result, tgtLen,inst->getWOps()[0]->getAlign());
PCodeInst* newInst;
PCodeBlock* block = inst->block;
newInst = block->insertNewInstAfter(inst,
PCIT::MOVE_MBIGS_MBIGS_IBIN32S_IBIN32S);
newInst->code[1] = inst->code[1];
newInst->code[2] = inst->code[2];
newInst->code[3] = 1;
newInst->code[4] = *off;
newInst->code[5] = tgtLen;
newInst->code[6] = tgtLen;
newInst->reloadOperands(this);
// Attempt to update reaching defs info.
if (rDefsAvailable)
updateReachingDefs(block, op1->getBvIndex(), inst, newInst);
block->deleteInst(inst);
inst = newInst;
}
break;
}
case PCIT::MOVE_MBIN32S_IBIN32S:
{
PCodeInst* newInst;
PCodeBlock* block = inst->block;
op1 = inst->getWOps()[0];
// Folding inst into same-sized moves is useful for copy propagation, and
// that being only if the write operand is a temp.
if (!op1->isTemp())
break;
newInst = block->insertNewInstAfter(inst, PCIT::MOVE_MBIN32U_MBIN32U);
newInst->code[1] = inst->code[1];
newInst->code[2] = inst->code[2];
newInst->code[3] = 1;
newInst->code[4] = addNewIntConstant(inst->code[3], 4);
newInst->reloadOperands(this);
// Attempt to update reaching defs info.
if (rDefsAvailable)
updateReachingDefs(block, op1->getBvIndex(), inst, newInst);
block->deleteInst(inst);
inst = newInst;
break;
}
case PCIT::MOVE_MBIN64S_MBIN16U:
case PCIT::MOVE_MBIN64S_MBIN16S:
case PCIT::MOVE_MBIN64S_MBIN32S:
case PCIT::MOVE_MBIN64S_MBIN32U:
case PCIT::MOVE_MBIN32U_MBIN16U:
case PCIT::MOVE_MBIN32S_MBIN16U:
case PCIT::MOVE_MBIN32U_MBIN16S:
case PCIT::MOVE_MBIN32S_MBIN16S:
case PCIT::MOVE_MBIN16U_MBIN8:
{
// Folding inst into same-sized moves is useful for copy propagation, and
// that being only if the write operand is a temp.
if (!inst->getWOps()[0]->isTemp())
break;
op1 = inst->getROps()[0];
if (op1->isConst()) {
Int64 value = getIntConstValue(op1);
// Re-define the instruction and reload operands
switch (inst->getWOps()[0]->getType()) {
case PCIT::MBIN64S:
inst->code[0] = PCIT::MOVE_MBIN64S_MBIN64S;
inst->code[4] = addNewIntConstant(value, 8);
break;
case PCIT::MBIN32U:
case PCIT::MBIN32S:
inst->code[0] = PCIT::MOVE_MBIN32U_MBIN32U;
inst->code[4] = addNewIntConstant(value, 4);
break;
case PCIT::MBIN16U:
inst->code[0] = PCIT::MOVE_MBIN16U_MBIN16U;
inst->code[4] = addNewIntConstant(value, 2);
break;
}
inst->reloadOperands(this);
}
break;
}
case PCIT::MOVE_MFLT64_MBIN16S:
case PCIT::MOVE_MFLT64_MBIN32S:
case PCIT::MOVE_MFLT64_MBIN64S:
case PCIT::MOVE_MFLT64_MFLT32:
{
// Folding inst into same-sized moves is useful for copy propagation, and
// that being only if the write operand is a temp.
if (!inst->getWOps()[0]->isTemp())
break;
op1 = inst->getROps()[0];
if (op1->isConst()) {
double fvalue =
(inst->getROps()[0]->getType() == PCIT::MFLT32)
? (double)(getFloatConstValue(op1))
: (double)(getIntConstValue(op1));
// Re-define the instruction and reload operands
inst->code[0] = PCIT::MOVE_MBIN64S_MBIN64S;
inst->code[4] = addNewFloatConstant(fvalue, 8);
inst->reloadOperands(this);
}
break;
}
case PCIT::MUL_MBIN16S_MBIN16S_MBIN16S:
case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S:
case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S:
case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S:
case PCIT::MUL_MBIN64S_MBIN16S_MBIN32S:
case PCIT::MUL_MBIN64S_MBIN32S_MBIN32S:
case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S:
for (i=0; i < inst->getROps().entries(); i++) {
op1 = inst->getROps()[i];
if (op1->isConst() && (getIntConstValue(op1) == 1)) {
switch (opc) {
case PCIT::MUL_MBIN64S_MBIN16S_MBIN32S:
inst->code[0] = (i == 0) ? PCIT::MOVE_MBIN64S_MBIN32S :
PCIT::MOVE_MBIN64S_MBIN16S;
break;
case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S:
inst->code[0] = (i == 0) ? PCIT::MOVE_MBIN32U_MBIN32U :
PCIT::MOVE_MBIN32S_MBIN16S;
break;
case PCIT::MUL_MBIN16S_MBIN16S_MBIN16S:
inst->code[0] = PCIT::MOVE_MBIN16U_MBIN16U;
break;
case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S:
inst->code[0] = PCIT::MOVE_MBIN32U_MBIN32U;
break;
case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S:
inst->code[0] = PCIT::MOVE_MBIN32S_MBIN16S;
break;
case PCIT::MUL_MBIN64S_MBIN32S_MBIN32S:
inst->code[0] = PCIT::MOVE_MBIN64S_MBIN32S;
break;
case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S:
inst->code[0] = PCIT::MOVE_MBIN64S_MBIN64S;
break;
}
inst->code[3] = inst->getROps()[(i+1)%2]->getStackIndex();
inst->code[4] = inst->getROps()[(i+1)%2]->getOffset();
inst->reloadOperands(this);
// Try to fold the move even further
return constantFold(inst, rDefsAvailable);
}
}
op1 = inst->getROps()[0];
op2 = inst->getROps()[1];
if (op1->isConst() && op2->isConst())
{
Int64 x = getIntConstValue(op1);
Int64 y = getIntConstValue(op2);
Int64 value = EXP_FIXED_OV_MUL(x, y, &ov);
if (ov)
return inst;
Int32 offset = addNewIntConstant(value, inst->getWOps()[0]->getLen());
inst->code[0] = inst->generateCopyMoveOpc(
inst->getWOps()[0]->getType());
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
}
break;
case PCIT::EQ_MBIN32S_MASCII_MASCII:
case PCIT::LT_MBIN32S_MASCII_MASCII:
case PCIT::LE_MBIN32S_MASCII_MASCII:
case PCIT::GT_MBIN32S_MASCII_MASCII:
case PCIT::GE_MBIN32S_MASCII_MASCII:
{
op1 = inst->getROps()[0];
op2 = inst->getROps()[1];
if (op1->isConst() && op2->isConst())
{
Int32 z, len;
char* x = getStringConstValue(op1, &len);
char* y = getStringConstValue(op2, &len);
z = memcmp(x, y, op1->getLen());
switch (opc) {
case PCIT::EQ_MBIN32S_MASCII_MASCII:
z = (z == 0);
break;
case PCIT::LT_MBIN32S_MASCII_MASCII:
z = (z < 0);
break;
case PCIT::LE_MBIN32S_MASCII_MASCII:
z = (z <= 0);
break;
case PCIT::GT_MBIN32S_MASCII_MASCII:
z = (z > 0);
break;
case PCIT::GE_MBIN32S_MASCII_MASCII:
z = (z >= 0);
break;
}
Int32 offset = addNewIntConstant(z, 4);
inst->code[0] = inst->generateCopyMoveOpc(PCIT::MBIN32S);
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
}
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_MBIN16S_MBIN32U:
case PCIT::LE_MBIN32S_MBIN16U_MBIN16S:
case PCIT::LE_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_MBIN16S_MBIN32U:
case PCIT::GE_MBIN32S_MBIN16U_MBIN16S:
case PCIT::GE_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_MBIN16U_MBIN16U:
case PCIT::LT_MBIN32S_MBIN16U_MBIN32U:
case PCIT::LT_MBIN32S_MBIN32U_MBIN32U:
case PCIT::LT_MBIN32S_MBIN16S_MBIN32U:
case PCIT::LT_MBIN32S_MBIN16U_MBIN16S:
case PCIT::LT_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_MBIN16S_MBIN32U:
case PCIT::GT_MBIN32S_MBIN16U_MBIN16S:
case PCIT::GT_MBIN32S_MBIN64S_MBIN64S:
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_MBIN16S_MBIN32U:
case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S:
case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S:
case PCIT::NE_MBIN32S_MBIN64S_MBIN64S:
case PCIT::NE_MBIN32S_MBIN16S_MBIN16S:
{
op1 = inst->getROps()[0];
op2 = inst->getROps()[1];
if (op1->isConst() && op2->isConst())
{
Int32 z = 0;
Int64 x = getIntConstValue(op1);
Int64 y = getIntConstValue(op2);
switch (opc) {
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_MBIN16S_MBIN32U:
case PCIT::LE_MBIN32S_MBIN16U_MBIN16S:
case PCIT::LE_MBIN32S_MBIN64S_MBIN64S:
z = (x <= y) ? 1 : 0;
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_MBIN16S_MBIN32U:
case PCIT::GE_MBIN32S_MBIN16U_MBIN16S:
case PCIT::GE_MBIN32S_MBIN64S_MBIN64S:
z = (x >= y) ? 1 : 0;
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_MBIN16S_MBIN32U:
case PCIT::LT_MBIN32S_MBIN16U_MBIN16S:
case PCIT::LT_MBIN32S_MBIN64S_MBIN64S:
z = (x < y) ? 1 : 0;
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_MBIN16S_MBIN32U:
case PCIT::GT_MBIN32S_MBIN16U_MBIN16S:
case PCIT::GT_MBIN32S_MBIN64S_MBIN64S:
z = (x > y) ? 1 : 0;
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_MBIN16S_MBIN32U:
case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S:
case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S:
z = (x == y) ? 1 : 0;
break;
case PCIT::NE_MBIN32S_MBIN64S_MBIN64S:
case PCIT::NE_MBIN32S_MBIN16S_MBIN16S:
z = (x != y) ? 1 : 0;
break;
}
Int32 offset = addNewIntConstant(z, 4);
inst->code[0] = inst->generateCopyMoveOpc(PCIT::MBIN32S);
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
}
break;
}
case PCIT::ADD_MBIN16S_MBIN16S_MBIN16S:
case PCIT::ADD_MBIN32S_MBIN32S_MBIN32S:
case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S:
case PCIT::ADD_MBIN32S_MBIN16S_MBIN16S:
case PCIT::ADD_MBIN32S_MBIN16S_MBIN32S:
case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S:
{
op1 = inst->getROps()[0];
op2 = inst->getROps()[1];
if (op1->isConst() && op2->isConst())
{
Int64 x = getIntConstValue(op1);
Int64 y = getIntConstValue(op2);
Int64 value = EXP_FIXED_OV_ADD(x, y, &ov);
if (ov)
return inst;
Int32 offset = addNewIntConstant(value, inst->getWOps()[0]->getLen());
inst->code[0] = inst->generateCopyMoveOpc(
inst->getWOps()[0]->getType());
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
}
break;
}
case PCIT::SUB_MBIN16S_MBIN16S_MBIN16S:
case PCIT::SUB_MBIN32S_MBIN32S_MBIN32S:
case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S:
case PCIT::SUB_MBIN32S_MBIN16S_MBIN16S:
case PCIT::SUB_MBIN32S_MBIN16S_MBIN32S:
case PCIT::SUB_MBIN32S_MBIN32S_MBIN16S:
{
op1 = inst->getROps()[0];
op2 = inst->getROps()[1];
if (op1->isConst() && op2->isConst())
{
Int64 x = getIntConstValue(op1);
Int64 y = getIntConstValue(op2);
Int64 value = EXP_FIXED_OV_SUB(x, y, &ov);
if (ov)
return inst;
Int32 offset = addNewIntConstant(value, inst->getWOps()[0]->getLen());
inst->code[0] = inst->generateCopyMoveOpc(
inst->getWOps()[0]->getType());
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
}
break;
}
case PCIT::MUL_MFLT64_MFLT64_MFLT64:
case PCIT::ADD_MFLT64_MFLT64_MFLT64:
case PCIT::SUB_MFLT64_MFLT64_MFLT64:
case PCIT::DIV_MFLT64_MFLT64_MFLT64:
{
op1 = inst->getROps()[0];
op2 = inst->getROps()[1];
if (op1->isConst() && op2->isConst()) {
double x = getFloatConstValue(op1);
double y = getFloatConstValue(op2);
double res = 0.0;
Int16 ov = 0;
switch (opc) {
case PCIT::MUL_MFLT64_MFLT64_MFLT64:
res = MathReal64Mul(x, y, &ov);
break;
case PCIT::ADD_MFLT64_MFLT64_MFLT64:
res = MathReal64Add(x, y, &ov);
break;
case PCIT::SUB_MFLT64_MFLT64_MFLT64:
res = MathReal64Sub(x, y, &ov);
break;
case PCIT::DIV_MFLT64_MFLT64_MFLT64:
res = MathReal64Div(x, y, &ov);
break;
}
if (ov)
return inst;
// FIXME: I think we need to appropriately support a MOVE_MFLT64_MFLT64
// instruction so that Native Expressions doesn't get confused.
Int32 offset = addNewFloatConstant(res, 8);
inst->code[0] = PCIT::MOVE_MBIN64S_MBIN64S;
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
}
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:
{
op1 = inst->getROps()[0];
if (op1->isConst()) {
Int32 len;
char* x;
UInt32 flags = ExHDPHash::NO_FLAGS;
if (opc == PCIT::HASH_MBIN32U_MATTR5) {
x = getStringConstValue(op1, &len);
// Reduce length if padding exists.
while ((len > 0) && (x[len-1] == ' '))
len--;
}
else {
len = op1->getLen();
x = (char*)getPtrConstValue(op1);
flags = inst->code[5];
}
UInt32 res = ExHDPHash::hash(x, flags, len);
Int32 offset = addNewIntConstant(res, 4);
inst->code[0] = inst->generateCopyMoveOpc(PCIT::MBIN32S);
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
}
break;
}
case PCIT::RANGE_LOW_S32S64:
case PCIT::RANGE_HIGH_S32S64:
case PCIT::RANGE_LOW_U32S64:
case PCIT::RANGE_HIGH_U32S64:
case PCIT::RANGE_LOW_S64S64:
case PCIT::RANGE_HIGH_S64S64:
case PCIT::RANGE_LOW_S16S64:
case PCIT::RANGE_HIGH_S16S64:
case PCIT::RANGE_MFLT64:
{
Int64 x, y;
NABoolean error = TRUE; // Assume range instruction is needed
PCodeOperand* op = inst->getROps()[0];
// Only range instructions with const operands can be removed
if (!op->isConst())
break;
if (opc != PCIT::RANGE_MFLT64) {
x = getIntConstValue(op);
y = (*(Int64*)&inst->code[3]);
}
switch (opc) {
case PCIT::RANGE_LOW_S32S64:
case PCIT::RANGE_LOW_U32S64:
case PCIT::RANGE_LOW_S64S64:
case PCIT::RANGE_LOW_S16S64:
error = (x < y);
break;
case PCIT::RANGE_HIGH_S32S64:
case PCIT::RANGE_HIGH_U32S64:
case PCIT::RANGE_HIGH_S64S64:
case PCIT::RANGE_HIGH_S16S64:
error = (x > y);
break;
case PCIT::RANGE_MFLT64:
error = FALSE;
break;
}
if (!error) {
PCodeBlock* block = inst->block;
block->deleteInst(inst);
inst = NULL;
}
break;
}
case PCIT::COMP_MBIN32S_MATTR5_MATTR5_IBIN32S:
{
op1 = inst->getROps()[0];
op2 = inst->getROps()[1];
if (!op1->isConst() || !op2->isConst())
break;
Int32 len1, len2;
char* str1 = getStringConstValue(op1, &len1);
char* str2 = getStringConstValue(op2, &len2);
Int32 compTable[6][3] = {
/* ITM_EQUAL */ {0, 1, 0},
/* ITM_NOT_EQUAL */ {1, 0, 1},
/* ITM_LESS */ {1, 0, 0},
/* ITM_LESS_EQ */ {1, 1, 0},
/* ITM_GREATER */ {0, 0, 1},
/* ITM_GREATER_EQ */ {0, 1, 1}
};
// Set table pointer to appropriate position based on operation
Int32* table = &(compTable[inst->code[13] - ITM_EQUAL][1]);
Int32 compCode = charStringCompareWithPad(str1, len1, str2, len2, ' ');
Int32 res = table[compCode];
Int32 offset = addNewIntConstant(res, 4);
inst->code[0] = inst->generateCopyMoveOpc(PCIT::MBIN32S);
inst->code[3] = 1;
inst->code[4] = offset;
inst->reloadOperands(this);
break;
}
case PCIT::GENFUNC_MATTR5_MATTR5_IBIN32S:
{
Int32 len;
Int32 subOpc = inst->code[11];
// Get source operand and check if constant.
op2 = inst->getROps()[0];
if (!op2->isConst())
break;
// Get tgt operand.
op1 = inst->getWOps()[0];
switch (subOpc) {
case ITM_TRIM:
case ITM_LTRIM:
case ITM_RTRIM:
case ITM_UPPER:
case ITM_LOWER:
{
Int32 startIdx = 0;
char* fromStr = NULL;
NABoolean fromStrAllocated = FALSE;
PCodeInst* newInst;
PCodeBlock* block = inst->block;
// Get source string and len (initial target length)
char* str = getStringConstValue(op2, &len);
CollIndex tgtLen = len;
if ((subOpc == ITM_LOWER) || (subOpc == ITM_UPPER))
{
fromStr = (char*) new(heap_) char[tgtLen];
for (i=0; i < tgtLen; i++)
fromStr[i] = (subOpc == ITM_UPPER)
? TOUPPER(str[i]) : TOLOWER(str[i]);
fromStrAllocated = TRUE;
}
else {
// Set string up to first non-space
if ((subOpc == ITM_TRIM) || (subOpc == ITM_LTRIM)) {
for (i=0; i < (CollIndex)len; i++, startIdx++, tgtLen--)
if (str[i] != ' ')
break;
}
// Set string up to last non-space
if ((subOpc == ITM_TRIM) || (subOpc == ITM_RTRIM)) {
if ( len > 0 ) // Protect against 0-length strings
{
for (i=len-1; i > (CollIndex)startIdx; i--, tgtLen--)
if (str[i] != ' ')
break;
}
}
// Set "fromStr" to be "str" so that code below works for all cases.
fromStr = str;
}
if (op1->isVarchar()) {
// Allocate new varchar string with 2 bytes for vc len
char* newStr = (char*) new(heap_) char[2 + tgtLen];
*((Int16*)(newStr)) = (Int16)tgtLen;
if (tgtLen > 0)
str_cpy_all(newStr + 2, &fromStr[startIdx], tgtLen);
CollIndex* off = addConstant((void*)newStr, tgtLen + 2, 2);
Int32 comboLen = 0;
char* comboPtr = (char*)(&comboLen);
comboPtr[0] = 0; // no null
comboPtr[1] = 2; // vc length is 2 bytes
newInst = block->insertNewInstAfter(inst, PCIT::MOVE_MATTR5_MATTR5);
newInst->code[1] = inst->code[1];
newInst->code[2] = inst->code[2];
newInst->code[3] = inst->code[3];
newInst->code[4] = inst->code[4];
newInst->code[5] = inst->code[5];
newInst->code[6] = 1;
newInst->code[7] = *off + 2; // Up 2 to get to str itself
newInst->code[8] = -1; // voa
newInst->code[9] = op1->getVcMaxLen(); // tgt/src share max vc len
newInst->code[10] = comboLen;
NADELETEBASIC(newStr, heap_);
}
else {
CollIndex* off = addConstant((void*)fromStr, tgtLen, 1);
newInst =
block->insertNewInstAfter(inst, PCIT::MOVE_MBIN8_MBIN8_IBIN32S);
newInst->code[1] = inst->code[1];
newInst->code[2] = inst->code[2];
newInst->code[3] = 1;
newInst->code[4] = *off;
newInst->code[5] = tgtLen;
}
newInst->reloadOperands(this);
// Attempt to update reaching defs info.
if (rDefsAvailable)
updateReachingDefs(block, op1->getBvIndex(), inst, newInst);
block->deleteInst(inst);
inst = newInst;
// Cleanup if needed.
if (fromStrAllocated)
NADELETEBASIC(fromStr, heap_);
break;
}
default:
break;
}
}
default:
break;
}
return inst;
}