TR::Register * OMR::ARM64::TreeEvaluator::imulEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Node *secondChild = node->getSecondChild(); TR::Register *trgReg; if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL) { int32_t value = secondChild->getInt(); if (value > 0 && cg->convertMultiplyToShift(node)) { // The multiply has been converted to a shift. trgReg = cg->evaluate(node); return trgReg; } else { trgReg = cg->allocateRegister(); mulConstant32(node, trgReg, src1Reg, value, cg); } } else { TR::Register *src2Reg = cg->evaluate(secondChild); trgReg = cg->allocateRegister(); generateMulInstruction(cg, node, trgReg, src1Reg, src2Reg); } firstChild->decReferenceCount(); secondChild->decReferenceCount(); node->setRegister(trgReg); return trgReg; }
static TR::Register *addOrSubInteger(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Node *secondChild = node->getSecondChild(); TR::Register *trgReg = cg->allocateRegister(); bool isAdd = node->getOpCode().isAdd(); if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL) { int32_t value = secondChild->getInt(); if (constantIsUnsignedImm12(value)) { generateTrg1Src1ImmInstruction(cg, isAdd ? TR::InstOpCode::addimmw : TR::InstOpCode::subimmw, node, trgReg, src1Reg, value); } else { TR::Register *tmpReg = cg->allocateRegister(); loadConstant32(cg, node, value, tmpReg); generateTrg1Src2Instruction(cg, isAdd ? TR::InstOpCode::addw : TR::InstOpCode::subw, node, trgReg, src1Reg, tmpReg); cg->stopUsingRegister(tmpReg); } } else { TR::Register *src2Reg = cg->evaluate(secondChild); generateTrg1Src2Instruction(cg, isAdd ? TR::InstOpCode::addw : TR::InstOpCode::subw, node, trgReg, src1Reg, src2Reg); } node->setRegister(trgReg); firstChild->decReferenceCount(); secondChild->decReferenceCount(); return trgReg; }
static TR::Register *shiftHelper(TR::Node *node, TR::ARM64ShiftCode shiftType, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = node->getSecondChild(); TR::ILOpCodes secondOp = secondChild->getOpCodeValue(); TR::Register *srcReg = cg->evaluate(firstChild); TR::Register *trgReg = cg->allocateRegister(); bool is64bit = node->getDataType().isInt64(); TR::InstOpCode::Mnemonic op; if (secondOp == TR::iconst || secondOp == TR::iuconst) { int32_t value = secondChild->getInt(); uint32_t shift = is64bit ? (value & 0x3F) : (value & 0x1F); switch (shiftType) { case TR::SH_LSL: generateLogicalShiftLeftImmInstruction(cg, node, trgReg, srcReg, shift); break; case TR::SH_LSR: generateLogicalShiftRightImmInstruction(cg, node, trgReg, srcReg, shift); break; case TR::SH_ASR: generateArithmeticShiftRightImmInstruction(cg, node, trgReg, srcReg, shift); break; default: TR_ASSERT(false, "Unsupported shift type."); } } else { TR::Register *shiftAmountReg = cg->evaluate(secondChild); switch (shiftType) { case TR::SH_LSL: op = is64bit ? TR::InstOpCode::lslvx : TR::InstOpCode::lslvw; break; case TR::SH_LSR: op = is64bit ? TR::InstOpCode::lsrvx : TR::InstOpCode::lsrvw; break; case TR::SH_ASR: op = is64bit ? TR::InstOpCode::asrvx : TR::InstOpCode::asrvw; break; default: TR_ASSERT(false, "Unsupported shift type."); } generateTrg1Src2Instruction(cg, op, node, trgReg, srcReg, shiftAmountReg); } node->setRegister(trgReg); firstChild->decReferenceCount(); secondChild->decReferenceCount(); return trgReg; }
TR::Register * OMR::ARM64::TreeEvaluator::imulhEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Node *secondChild = node->getSecondChild(); TR::Register *src2Reg; TR::Register *trgReg = cg->allocateRegister(); TR::Register *tmpReg = NULL; TR::Register *zeroReg = cg->allocateRegister(); TR::RegisterDependencyConditions *cond = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory()); addDependency(cond, zeroReg, TR::RealRegister::xzr, TR_GPR, cg); // imulh is generated for constant idiv and the second child is the magic number // assume magic number is usually a large odd number with little optimization opportunity if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL) { int32_t value = secondChild->getInt(); src2Reg = tmpReg = cg->allocateRegister(); loadConstant32(cg, node, value, src2Reg); } else { src2Reg = cg->evaluate(secondChild); } generateTrg1Src3Instruction(cg, TR::InstOpCode::smaddl, node, trgReg, src1Reg, src2Reg, zeroReg, cond); cg->stopUsingRegister(zeroReg); /* logical shift right by 32 bits */ uint32_t imm = 0x183F; // N=1, immr=32, imms=63 generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ubfmx, node, trgReg, trgReg, imm); if (tmpReg) { cg->stopUsingRegister(tmpReg); } firstChild->decReferenceCount(); secondChild->decReferenceCount(); node->setRegister(trgReg); return trgReg; }
// also handles lrol TR::Register * OMR::ARM64::TreeEvaluator::irolEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = node->getSecondChild(); TR::Register *trgReg = cg->gprClobberEvaluate(firstChild); bool is64bit = node->getDataType().isInt64(); TR::InstOpCode::Mnemonic op; if (secondChild->getOpCode().isLoadConst()) { int32_t value = secondChild->getInt(); uint32_t shift = is64bit ? (value & 0x3F) : (value & 0x1F); if (shift != 0) { shift = is64bit ? (64 - shift) : (32 - shift); // change ROL to ROR op = is64bit ? TR::InstOpCode::extrx : TR::InstOpCode::extrw; // ROR is an alias of EXTR generateTrg1Src2ShiftedInstruction(cg, op, node, trgReg, trgReg, trgReg, TR::SH_LSL, shift); } } else { TR::Register *shiftAmountReg = cg->evaluate(secondChild); generateNegInstruction(cg, node, shiftAmountReg, shiftAmountReg); // change ROL to ROR if (is64bit) { // 32->64 bit sign extension: SXTW is alias of SBFM uint32_t imm = 0x101F; // N=1, immr=0, imms=31 generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sbfmx, node, shiftAmountReg, shiftAmountReg, imm); } op = is64bit ? TR::InstOpCode::rorvx : TR::InstOpCode::rorvw; generateTrg1Src2Instruction(cg, op, node, trgReg, trgReg, shiftAmountReg); } node->setRegister(trgReg); firstChild->decReferenceCount(); secondChild->decReferenceCount(); return trgReg; }
uint8_t *TR::PPCArrayCopyCallSnippet::emitSnippetBody() { TR::Node *node = getNode(); TR_ASSERT(node->getOpCodeValue() == TR::arraycopy && node->getChild(2)->getOpCode().isLoadConst(), "only valid for arraycopies with a constant length\n"); uint8_t *buffer = cg()->getBinaryBufferCursor(); getSnippetLabel()->setCodeLocation(buffer); TR::RealRegister *lengthReg = cg()->machine()->getRealRegister(_lengthRegNum); TR::Node *lengthNode = node->getChild(2); int64_t byteLen = (lengthNode->getType().isInt32() ? lengthNode->getInt() : lengthNode->getLongInt()); TR::InstOpCode opcode; // li lengthReg, #byteLen opcode.setOpCodeValue(TR::InstOpCode::li); buffer = opcode.copyBinaryToBuffer(buffer); lengthReg->setRegisterFieldRT((uint32_t *)buffer); TR_ASSERT(byteLen <= UPPER_IMMED,"byteLen too big to encode\n"); *(int32_t *)buffer |= byteLen; buffer += 4; return TR::PPCHelperCallSnippet::genHelperCall(buffer); }
void TR::PPCTrg1ImmInstruction::addMetaDataForCodeAddress(uint8_t *cursor) { TR::Compilation *comp = cg()->comp(); if (std::find(comp->getStaticPICSites()->begin(), comp->getStaticPICSites()->end(), this) != comp->getStaticPICSites()->end()) { TR::Node *node = getNode(); cg()->jitAddPicToPatchOnClassUnload((void *)(TR::Compiler->target.is64Bit()?node->getLongInt():node->getInt()), (void *)cursor); } if (std::find(comp->getStaticMethodPICSites()->begin(), comp->getStaticMethodPICSites()->end(), this) != comp->getStaticMethodPICSites()->end()) { TR::Node *node = getNode(); cg()->jitAddPicToPatchOnClassUnload((void *) (cg()->fe()->createResolvedMethod(cg()->trMemory(), (TR_OpaqueMethodBlock *) (TR::Compiler->target.is64Bit()?node->getLongInt():node->getInt()), comp->getCurrentMethod())->classOfMethod()), (void *)cursor); } }
bool OMR::Simplifier::isBoundDefinitelyGELength(TR::Node *boundChild, TR::Node *lengthChild) { TR::ILOpCodes boundOp = boundChild->getOpCodeValue(); if (boundOp == TR::iadd) { TR::Node *first = boundChild->getFirstChild(); TR::Node *second = boundChild->getSecondChild(); if (first == lengthChild) { TR::ILOpCodes secondOp = second->getOpCodeValue(); if (second->getOpCode().isArrayLength() || secondOp == TR::bu2i || secondOp == TR::su2i || (secondOp == TR::iconst && second->getInt() >= 0) || (secondOp == TR::iand && second->getSecondChild()->getOpCodeValue() == TR::iconst && (second->getSecondChild()->getInt() & 80000000) == 0) || (secondOp == TR::iushr && second->getSecondChild()->getOpCodeValue() == TR::iconst && (second->getSecondChild()->getInt() & 0x1f) > 0)) { return true; } } else if (second == lengthChild) { TR::ILOpCodes firstOp = first->getOpCodeValue(); if (first->getOpCode().isArrayLength() || firstOp == TR::bu2i || firstOp == TR::su2i || (firstOp == TR::iand && first->getSecondChild()->getOpCodeValue() == TR::iconst && (first->getSecondChild()->getInt() & 80000000) == 0) || (firstOp == TR::iushr && first->getSecondChild()->getOpCodeValue() == TR::iconst && (first->getSecondChild()->getInt() & 0x1f) > 0)) { return true; } } } else if (boundOp == TR::isub) { TR::Node *first = boundChild->getFirstChild(); TR::Node *second = boundChild->getSecondChild(); if (first == lengthChild) { TR::ILOpCodes secondOp = second->getOpCodeValue(); if ((secondOp == TR::iconst && second->getInt() < 0) || (secondOp == TR::ior && second->getSecondChild()->getOpCodeValue() == TR::iconst && (second->getSecondChild()->getInt() & 0x80000000) != 0)) { return true; } } } return false; }
TR_ExpressionsSimplification::LoopInfo* TR_ExpressionsSimplification::findLoopInfo(TR_RegionStructure* region) { ListIterator<TR::CFGEdge> exitEdges(®ion->getExitEdges()); if (region->getExitEdges().getSize() != 1) { if (trace()) traceMsg(comp(), "Region with more than 1 exit edges can't be handled\n"); return 0; } TR_StructureSubGraphNode* exitNode = toStructureSubGraphNode(exitEdges.getFirst()->getFrom()); if (!exitNode->getStructure()->asBlock()) { if (trace()) traceMsg(comp(), "The exit block can't be found\n"); return 0; } TR::Block *exitBlock = exitNode->getStructure()->asBlock()->getBlock(); TR::Node *lastTreeInExitBlock = exitBlock->getLastRealTreeTop()->getNode(); if (trace()) { traceMsg(comp(), "The exit block is %d\n", exitBlock->getNumber()); traceMsg(comp(), "The branch node is %p\n", lastTreeInExitBlock); } if (!lastTreeInExitBlock->getOpCode().isBranch()) { if (trace()) traceMsg(comp(), "The branch node couldn't be found\n"); return 0; } if (lastTreeInExitBlock->getNumChildren() < 2) { if (trace()) traceMsg(comp(), "The branch node has less than 2 children\n"); return 0; } TR::Node *firstChildOfLastTree = lastTreeInExitBlock->getFirstChild(); TR::Node *secondChildOfLastTree = lastTreeInExitBlock->getSecondChild(); if (!firstChildOfLastTree->getOpCode().hasSymbolReference()) { if (trace()) traceMsg(comp(), "The branch node's first child node %p - its opcode does not have a symbol reference\n", firstChildOfLastTree); return 0; } TR::SymbolReference *firstChildSymRef = firstChildOfLastTree->getSymbolReference(); if (trace()) traceMsg(comp(), "Symbol Reference: %p Symbol: %p\n", firstChildSymRef, firstChildSymRef->getSymbol()); // Locate the induction variable that matches with the exit node symbol // TR_InductionVariable *indVar = region->findMatchingIV(firstChildSymRef); if (!indVar) return 0; if (!indVar->getIncr()->asIntConst()) { if (trace()) traceMsg(comp(), "Increment is not a constant\n"); return 0; } int32_t increment = indVar->getIncr()->getLowInt(); _visitCount = comp()->incVisitCount(); bool indVarWrittenAndUsedUnexpectedly = false; if (firstChildOfLastTree->getReferenceCount() > 1) { TR::TreeTop *cursorTreeTopInExitBlock = exitBlock->getEntry(); TR::TreeTop *exitTreeTopInExitBlock = exitBlock->getExit(); bool loadSeen = false; while (cursorTreeTopInExitBlock != exitTreeTopInExitBlock) { TR::Node *cursorNode = cursorTreeTopInExitBlock->getNode(); if (checkForLoad(cursorNode, firstChildOfLastTree)) loadSeen = true; if (!cursorNode->getOpCode().isStore() && (cursorNode->getNumChildren() > 0)) cursorNode = cursorNode->getFirstChild(); if (cursorNode->getOpCode().isStore() && (cursorNode->getSymbolReference() == firstChildSymRef)) { indVarWrittenAndUsedUnexpectedly = true; if ((cursorNode->getFirstChild() == firstChildOfLastTree) || !loadSeen) indVarWrittenAndUsedUnexpectedly = false; else break; } cursorTreeTopInExitBlock = cursorTreeTopInExitBlock->getNextTreeTop(); } } if (indVarWrittenAndUsedUnexpectedly) { return 0; } int32_t lowerBound; int32_t upperBound = 0; TR::Node *bound = 0; bool equals = false; switch(lastTreeInExitBlock->getOpCodeValue()) { case TR::ificmplt: case TR::ificmpgt: equals = true; case TR::ificmple: case TR::ificmpge: if (!(indVar->getEntry() && indVar->getEntry()->asIntConst())) { if (trace()) traceMsg(comp(), "Entry value is not a constant\n"); return 0; } lowerBound = indVar->getEntry()->getLowInt(); if (secondChildOfLastTree->getOpCode().isLoadConst()) { upperBound = secondChildOfLastTree->getInt(); } else if (secondChildOfLastTree->getOpCode().isLoadVar()) { bound = secondChildOfLastTree; } else { if (trace()) traceMsg(comp(), "Second child is not a const or a load\n"); return 0; } return new (trStackMemory()) LoopInfo(bound, lowerBound, upperBound, increment, equals); default: if (trace()) traceMsg(comp(), "The condition has not been implemeted\n"); return 0; } return 0; }
TR::Register* OMR::X86::TreeEvaluator::SIMDgetvelemEvaluator(TR::Node* node, TR::CodeGenerator* cg) { TR::Node* firstChild = node->getChild(0); TR::Node* secondChild = node->getChild(1); TR::Register* srcVectorReg = cg->evaluate(firstChild); TR::Register* resReg = 0; TR::Register* lowResReg = 0; TR::Register* highResReg = 0; int32_t elementCount = -1; switch (firstChild->getDataType()) { case TR::VectorInt8: case TR::VectorInt16: TR_ASSERT(false, "unsupported vector type %s in SIMDgetvelemEvaluator.\n", firstChild->getDataType().toString()); break; case TR::VectorInt32: elementCount = 4; resReg = cg->allocateRegister(); break; case TR::VectorInt64: elementCount = 2; if (TR::Compiler->target.is32Bit()) { lowResReg = cg->allocateRegister(); highResReg = cg->allocateRegister(); resReg = cg->allocateRegisterPair(lowResReg, highResReg); } else { resReg = cg->allocateRegister(); } break; case TR::VectorFloat: elementCount = 4; resReg = cg->allocateSinglePrecisionRegister(TR_FPR); break; case TR::VectorDouble: elementCount = 2; resReg = cg->allocateRegister(TR_FPR); break; default: TR_ASSERT(false, "unrecognized vector type %s in SIMDgetvelemEvaluator.\n", firstChild->getDataType().toString()); } if (secondChild->getOpCode().isLoadConst()) { int32_t elem = secondChild->getInt(); TR_ASSERT(elem >= 0 && elem < elementCount, "Element can only be 0 to %u\n", elementCount - 1); uint8_t shufconst = 0x00; TR::Register* dstReg = 0; if (4 == elementCount) { /* * if elem = 0, access the most significant 32 bits (set shufconst to 0x03) * if elem = 1, access the second most significant 32 bits (set shufconst to 0x02) * if elem = 2, access the third most significant 32 bits (set shufconst to 0x01) * if elem = 3, access the least significant 32 bits (set shufconst to 0x00) */ shufconst = (uint8_t)((3 - elem) & 0x03); /* * the value to be read (indicated by shufconst) from srcVectorReg is splatted into all 4 slots in the dstReg * this puts the value we want in the least significant bits and the other bits should never be read. * for float, dstReg and resReg are the same because PSHUFD can work directly with TR_FPR registers * for Int32, the result needs to be moved from the dstReg to a TR_GPR resReg. */ if (TR::VectorInt32 == firstChild->getDataType()) { dstReg = cg->allocateRegister(TR_VRF); } else //TR::VectorFloat == firstChild->getDataType() { dstReg = resReg; } /* * if elem = 3, the value we want is already in the least significant 32 bits * as a result, a mov instruction is good enough and splatting the value is unnecessary */ if (3 == elem) { generateRegRegInstruction(MOVDQURegReg, node, dstReg, srcVectorReg, cg); } else { generateRegRegImmInstruction(PSHUFDRegRegImm1, node, dstReg, srcVectorReg, shufconst, cg); } if (TR::VectorInt32 == firstChild->getDataType()) { generateRegRegInstruction(MOVDReg4Reg, node, resReg, dstReg, cg); cg->stopUsingRegister(dstReg); } } else //2 == elementCount { /* * for double, dstReg and resReg are the same because PSHUFD can work directly with TR_FPR registers * for Int64, the result needs to be moved from the dstReg to a TR_GPR resReg. */ if (TR::VectorInt64 == firstChild->getDataType()) { dstReg = cg->allocateRegister(TR_VRF); } else //TR::VectorDouble == firstChild->getDataType() { dstReg = resReg; } /* * the value to be read needs to be in the least significant 64 bits. * if elem = 0, the value we want is in the most significant 64 bits and needs to be splatted into * the least significant 64 bits (the other bits affected by the splat are never read) * if elem = 1, the value we want is already in the least significant 64 bits * as a result, a mov instruction is good enough and splatting the value is unnecessary */ if (1 == elem) { generateRegRegInstruction(MOVDQURegReg, node, dstReg, srcVectorReg, cg); } else //0 == elem { generateRegRegImmInstruction(PSHUFDRegRegImm1, node, dstReg, srcVectorReg, 0x0e, cg); } if (TR::VectorInt64 == firstChild->getDataType()) { if (TR::Compiler->target.is32Bit()) { generateRegRegInstruction(MOVDReg4Reg, node, lowResReg, dstReg, cg); generateRegRegImmInstruction(PSHUFDRegRegImm1, node, dstReg, srcVectorReg, (0 == elem) ? 0x03 : 0x01, cg); generateRegRegInstruction(MOVDReg4Reg, node, highResReg, dstReg, cg); } else { generateRegRegInstruction(MOVQReg8Reg, node, resReg, dstReg, cg); } cg->stopUsingRegister(dstReg); } } } else { //TODO: handle non-constant second child case TR_ASSERT(false, "non-const second child not currently supported in SIMDgetvelemEvaluator.\n"); } node->setRegister(resReg); cg->decReferenceCount(firstChild); cg->decReferenceCount(secondChild); return resReg; }