/******************************************************************************* * Copyright IBM Corp. and others 2000 * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ * or the Apache License, Version 2.0 which accompanies this distribution * and is available at https://www.apache.org/licenses/LICENSE-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the * Eclipse Public License, v. 2.0 are satisfied: GNU General Public License, * version 2 with the GNU Classpath Exception [1] and GNU General Public * License, version 2 with the OpenJDK Assembly Exception [2]. * * [1] https://www.gnu.org/software/classpath/license.html * [2] https://openjdk.org/legal/assembly-exception.html * * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 *******************************************************************************/ #include "arm/codegen/ARMInstruction.hpp" #include "codegen/BackingStore.hpp" #include "codegen/CodeGenerator.hpp" #include "codegen/CodeGeneratorUtils.hpp" #include "codegen/GenerateInstructions.hpp" #include "codegen/Linkage.hpp" #include "codegen/Machine.hpp" #include "codegen/RealRegister.hpp" #include "codegen/Register.hpp" #include "codegen/RegisterDependency.hpp" #include "codegen/RegisterPair.hpp" #include "codegen/TreeEvaluator.hpp" #include "env/CompilerEnv.hpp" #include "il/Node.hpp" #include "il/Node_inlines.hpp" #include "il/TreeTop.hpp" #include "il/TreeTop_inlines.hpp" #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) // Helpers static bool noFPRA = false; // The current RA *does* seem to assign FP regs. Shall we change this to false? static TR::Register *moveToFloatRegister(TR::Node *node, TR::Register *srcReg, TR::CodeGenerator *cg) { // Move from regular registers to single floating point register if (srcReg->getKind() == TR_FPR) { TR_ASSERT(srcReg->isSinglePrecision(), "Expecting a single precision register\n"); return srcReg; } else // GPR { TR::Register *trgReg = cg->allocateSinglePrecisionRegister(); generateTrg1Src1Instruction(cg, TR::InstOpCode::fmsr, node, trgReg, srcReg); return trgReg; } } static TR::Register *moveToDoubleRegister(TR::Node *node, TR::Register *srcReg, TR::CodeGenerator *cg) { if (srcReg->getKind() == TR_FPR) { TR_ASSERT(!srcReg->isSinglePrecision(), "Expecting a double precision register\n"); return srcReg; } else // GPR { TR::Register *trgReg = cg->allocateRegister(TR_FPR); TR::RegisterPair *pair = srcReg->getRegisterPair(); generateTrg1Src2Instruction(cg, TR::InstOpCode::fmdrr, node, trgReg, pair->getLowOrder(), pair->getHighOrder()); return trgReg; } } static TR::Register *moveFromFloatRegister(TR::Node *node, TR::Register *srcReg, TR::CodeGenerator *cg) { TR::Register *trgReg = cg->allocateRegister(); generateTrg1Src1Instruction(cg, TR::InstOpCode::fmrs, node, trgReg, srcReg); return trgReg; } static TR::Register *moveFromDoubleRegister(TR::Node *node, TR::Register *srcReg, TR::CodeGenerator *cg) { TR::Register *lowReg = cg->allocateRegister(); TR::Register *highReg = cg->allocateRegister(); TR::RegisterPair *trgReg = cg->allocateRegisterPair(lowReg, highReg); generateTrg2Src1Instruction(cg, TR::InstOpCode::fmrrd, node, lowReg, highReg, srcReg); return trgReg; } static bool resultCanStayInFloatRegister(TR::Node *checkNode, TR::Node *node) { bool result = true; TR::Node *child= NULL; static bool disableVFPOpt = (feGetEnv("TR_DisableVFPOpt") != NULL); if (disableVFPOpt) return false; /* TODO: Memo - Below may hurt GRA when regassign for FP/Double is enabled in future. */ if (node->getReferenceCount() > 1) result = false; for (uint16_t i = 0; i < checkNode->getNumChildren() && result; i++) { child = checkNode->getChild(i); if (child->getOpCode().isCall()) result = false; else if (checkNode->getOpCodeValue() == TR::fstore && node->getOpCodeValue() == TR::fload) result = false; /* else if (checkNode->getOpCodeValue() == TR::dstore && node->getOpCodeValue() == TR::dload) result = false; */ else result = resultCanStayInFloatRegister(child, node); if (!result || child == node) break; } return result; } static TR::Register *singlePrecisionEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic opCode, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = NULL; TR::Register *src1Reg = cg->evaluate(firstChild); TR::Register *src2Reg = NULL; TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); TR::Register *trgReg = NULL; TR_ASSERT(node->getNumChildren() <= 2, "Not expecting more than 2 children in this node\n"); if (node->getNumChildren() == 2) { secondChild = node->getSecondChild(); src2Reg = cg->evaluate(secondChild); generateTrg1Src2Instruction(cg, opCode, node, floatTrgReg, moveToFloatRegister(node, src1Reg, cg), moveToFloatRegister(node, src2Reg, cg)); } else // 1 child { generateTrg1Src1Instruction(cg, opCode, node, floatTrgReg, moveToFloatRegister(node, src1Reg, cg)); } // Test with no RA, put values back in general registers, conforming to ABI if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); trgReg = floatTrgReg; } else { trgReg = moveFromFloatRegister(node, floatTrgReg, cg); cg->stopUsingRegister(floatTrgReg); } } else trgReg = floatTrgReg; node->setRegister(trgReg); cg->decReferenceCount(firstChild); if (node->getNumChildren() == 2) cg->decReferenceCount(secondChild); return trgReg; } static TR::Register *doublePrecisionEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic opCode, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = NULL; TR::Register *src1Reg = cg->evaluate(firstChild); TR::Register *src2Reg = NULL; TR::Register *doubleTrgReg = cg->allocateRegister(TR_FPR); TR::Register *trgReg = NULL; TR_ASSERT(node->getNumChildren() <= 2, "Not expecting more than 2 children in this node\n"); //TR_ASSERT(src1Reg->getRegisterPair(), "Expecting double value in a register pair\n"); if (node->getNumChildren() == 2) { secondChild = node->getSecondChild(); src2Reg = cg->evaluate(secondChild); //TR_ASSERT(src2Reg->getRegisterPair(), "Expecting double value in a register pair\n"); generateTrg1Src2Instruction(cg, opCode, node, doubleTrgReg, moveToDoubleRegister(node, src1Reg, cg), moveToDoubleRegister(node, src2Reg, cg)); } else // 1 child { generateTrg1Src1Instruction(cg, opCode, node, doubleTrgReg, moveToDoubleRegister(node, src1Reg, cg)); } // Test with no RA, put values back in general registers, conforming to ABI if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); trgReg = doubleTrgReg; } else { trgReg = moveFromDoubleRegister(node, doubleTrgReg, cg); cg->stopUsingRegister(doubleTrgReg); } } else trgReg = doubleTrgReg; node->setRegister(trgReg); cg->decReferenceCount(firstChild); if (node->getNumChildren() == 2) cg->decReferenceCount(secondChild); return trgReg; } static TR::Register *callLong2DoubleHelper(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *srcReg = cg->evaluate(child); TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(10, 10, cg->trMemory()); int i; TR::Register *highReg = cg->allocateRegister(); TR::Register *lowReg = cg->allocateRegister(); #if defined(__ARM_PCS_VFP) TR::Register *trgReg = cg->allocateRegister(TR_FPR); #else TR::Register *trgReg = cg->allocateRegisterPair(lowReg, highReg); #endif TR::Register *doubleTrgReg = NULL; if (cg->comp()->target().cpu.isLittleEndian()) { /* Little Endian */ dependencies->addPreCondition(srcReg->getHighOrder(), TR::RealRegister::gr1); dependencies->addPreCondition(srcReg->getLowOrder(), TR::RealRegister::gr0); #if defined(__ARM_PCS_VFP) dependencies->addPostCondition(trgReg, TR::RealRegister::fp0); for (i = 1; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateRegister(TR_FPR), realReg);//TODO live register } dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register #else dependencies->addPostCondition(trgReg->getHighOrder(), TR::RealRegister::gr1); dependencies->addPostCondition(trgReg->getLowOrder(), TR::RealRegister::gr0); #endif } else { /* Big Endian */ dependencies->addPreCondition(srcReg->getHighOrder(), TR::RealRegister::gr0); dependencies->addPreCondition(srcReg->getLowOrder(), TR::RealRegister::gr1); #if defined(__ARM_PCS_VFP) dependencies->addPostCondition(trgReg, TR::RealRegister::fp0); for (i = 1; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateRegister(TR_FPR), realReg);//TODO live register } dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register #else dependencies->addPostCondition(trgReg->getHighOrder(), TR::RealRegister::gr0); dependencies->addPostCondition(trgReg->getLowOrder(), TR::RealRegister::gr1); #endif } dependencies->stopAddingConditions(); generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMlong2Double)->getMethodAddress(), dependencies, cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMlong2Double)); if (noFPRA) { #if defined(__ARM_PCS_VFP) if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); doubleTrgReg = trgReg; } else { doubleTrgReg = moveFromDoubleRegister(node, trgReg, cg); cg->stopUsingRegister(trgReg); } #else doubleTrgReg = trgReg; #endif } else doubleTrgReg = trgReg; cg->decReferenceCount(child); cg->machine()->setLinkRegisterKilled(true); return doubleTrgReg; } static TR::Register *callLong2FloatHelper(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *srcReg = cg->evaluate(child); TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(10, 10, cg->trMemory()); int i; #if defined(__ARM_PCS_VFP) TR::Register *trgReg = cg->allocateSinglePrecisionRegister(); #else TR::Register *trgReg = cg->allocateRegister(); // Callout follows soft-float abi #endif TR::Register *floatTrgReg = NULL; if (cg->comp()->target().cpu.isLittleEndian()) { /* Little Endian */ dependencies->addPreCondition(srcReg->getHighOrder(), TR::RealRegister::gr1); dependencies->addPreCondition(srcReg->getLowOrder(), TR::RealRegister::gr0); #if defined(__ARM_PCS_VFP) dependencies->addPostCondition(trgReg, TR::RealRegister::fp0); for (i = 1; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateSinglePrecisionRegister(), realReg);//TODO live register } dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register #else dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register dependencies->addPostCondition(trgReg, TR::RealRegister::gr0); #endif } else { /* Big Endian */ dependencies->addPreCondition(srcReg->getHighOrder(), TR::RealRegister::gr0); dependencies->addPreCondition(srcReg->getLowOrder(), TR::RealRegister::gr1); #if defined(__ARM_PCS_VFP) dependencies->addPostCondition(trgReg, TR::RealRegister::fp0); for (i = 1; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateSinglePrecisionRegister(), realReg);//TODO live register } dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register #else dependencies->addPostCondition(trgReg, TR::RealRegister::gr0); dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register #endif } dependencies->stopAddingConditions(); generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMlong2Float)->getMethodAddress(), dependencies, cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMlong2Float)); if (noFPRA) { #if defined(__ARM_PCS_VFP) if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); floatTrgReg = trgReg; } else { floatTrgReg = moveFromFloatRegister(node, trgReg, cg); cg->stopUsingRegister(trgReg); } #else floatTrgReg = trgReg; #endif } else floatTrgReg = trgReg; cg->decReferenceCount(child); cg->machine()->setLinkRegisterKilled(true); return floatTrgReg; } static TR::Register *callDouble2LongHelper(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *doubleSrcReg = cg->evaluate(child); TR::Register *srcReg = NULL; TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(11, 11, cg->trMemory()); int i; TR::Register *highReg = cg->allocateRegister(); TR::Register *lowReg = cg->allocateRegister(); TR::Register *trgReg = cg->allocateRegisterPair(lowReg, highReg); #if defined(__ARM_PCS_VFP) // hard fp if (doubleSrcReg->getKind() == TR_GPR) { srcReg = moveToDoubleRegister(node, doubleSrcReg, cg); } else if (doubleSrcReg->getKind() == TR_FPR) { srcReg = doubleSrcReg; } else TR_ASSERT(0, "Unknown register type\n"); #else // soft fp if (doubleSrcReg->getKind() == TR_GPR) { srcReg = doubleSrcReg; } else if (doubleSrcReg->getKind() == TR_FPR) { srcReg = moveFromDoubleRegister(node, doubleSrcReg, cg); } else TR_ASSERT(0, "Unknown register type\n"); #endif if (cg->comp()->target().cpu.isLittleEndian()) { /* Little Endian */ #if defined(__ARM_PCS_VFP) dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register dependencies->addPreCondition(srcReg, TR::RealRegister::fp0); for (i = 0; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateRegister(TR_FPR), realReg);//TODO live register } #else dependencies->addPreCondition(srcReg->getHighOrder(), TR::RealRegister::gr1); dependencies->addPreCondition(srcReg->getLowOrder(), TR::RealRegister::gr0); #endif dependencies->addPostCondition(trgReg->getLowOrder(), TR::RealRegister::gr0); dependencies->addPostCondition(trgReg->getHighOrder(), TR::RealRegister::gr1); } else { /* Big Endian */ #if defined(__ARM_PCS_VFP) dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register dependencies->addPreCondition(srcReg, TR::RealRegister::fp0); for (i = 0; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateRegister(TR_FPR), realReg);//TODO live register } #else dependencies->addPreCondition(srcReg->getHighOrder(), TR::RealRegister::gr0); dependencies->addPreCondition(srcReg->getLowOrder(), TR::RealRegister::gr1); #endif dependencies->addPostCondition(trgReg->getHighOrder(), TR::RealRegister::gr0); dependencies->addPostCondition(trgReg->getLowOrder(), TR::RealRegister::gr1); } TR::addDependency(dependencies, NULL, TR::RealRegister::gr2, TR_GPR, cg); // Block r2 dependencies->stopAddingConditions(); generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMdouble2Long)->getMethodAddress(), dependencies, cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMdouble2Long)); //dependencies->stopUsingDepRegs(cg, trgReg); cg->decReferenceCount(child); cg->machine()->setLinkRegisterKilled(true); return trgReg; } static TR::Register *callFloat2LongHelper(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *floatSrcReg = cg->evaluate(child); TR::Register *srcReg = NULL; TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(11, 11, cg->trMemory()); int i; TR::Register *highReg = cg->allocateRegister(); TR::Register *lowReg = cg->allocateRegister(); TR::Register *trgReg = cg->allocateRegisterPair(lowReg, highReg); #if defined(__ARM_PCS_VFP) if (floatSrcReg->getKind() == TR_GPR) { srcReg = moveToFloatRegister(node, floatSrcReg, cg); } else if (floatSrcReg->getKind() == TR_FPR) { srcReg = floatSrcReg; } else TR_ASSERT(0, "Unknown register type\n"); #else //soft fp if (floatSrcReg->getKind() == TR_GPR) { srcReg = floatSrcReg; } else if (floatSrcReg->getKind() == TR_FPR) { srcReg = moveFromFloatRegister(node, floatSrcReg, cg); } else TR_ASSERT(0, "Unknown register type\n"); #endif if (cg->comp()->target().cpu.isLittleEndian()) { /* Little Endian */ #if defined(__ARM_PCS_VFP) dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register dependencies->addPreCondition(srcReg, TR::RealRegister::fp0); for (i = 0; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateSinglePrecisionRegister(), realReg);//TODO live register } #else dependencies->addPreCondition(srcReg, TR::RealRegister::gr0); #endif dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register dependencies->addPostCondition(trgReg->getHighOrder(), TR::RealRegister::gr1); dependencies->addPostCondition(trgReg->getLowOrder(), TR::RealRegister::gr0); } else { /* Big Endian */ #if defined(__ARM_PCS_VFP) dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr0);//TODO live register dependencies->addPreCondition(srcReg, TR::RealRegister::fp0); for (i = 0; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); dependencies->addPostCondition(cg->allocateSinglePrecisionRegister(), realReg);//TODO live register } #else dependencies->addPreCondition(srcReg, TR::RealRegister::gr0); #endif dependencies->addPreCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register dependencies->addPostCondition(trgReg->getHighOrder(), TR::RealRegister::gr0); dependencies->addPostCondition(trgReg->getLowOrder(), TR::RealRegister::gr1); } TR::addDependency(dependencies, NULL, TR::RealRegister::gr2, TR_GPR, cg); // Block r2 dependencies->stopAddingConditions(); generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMfloat2Long)->getMethodAddress(), dependencies, cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMfloat2Long)); //dependencies->stopUsingDepRegs(cg, trgReg); //cg->stopUsingRegister(dummyReg); cg->decReferenceCount(child); cg->machine()->setLinkRegisterKilled(true); return trgReg; } static TR::Register *callDoubleRemainderHelper(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = node->getSecondChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Register *src2Reg = cg->evaluate(secondChild); TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(10, 10, cg->trMemory()); int i; TR::Register *highReg = cg->allocateRegister(); TR::Register *lowReg = cg->allocateRegister(); #if defined(__ARM_PCS_VFP) TR::Register *trgReg = cg->allocateRegister(TR_FPR); #else TR::Register *trgReg = cg->allocateRegisterPair(lowReg, highReg); #endif TR::Register *doubleTrgReg = NULL; #if defined(__ARM_PCS_VFP) if (src1Reg->getKind() == TR_GPR) { src1Reg = moveToDoubleRegister(node, src1Reg, cg); } if (src2Reg->getKind() == TR_GPR) { src2Reg = moveToDoubleRegister(node, src2Reg, cg); } #else if (src1Reg->getKind() == TR_FPR) { src1Reg = moveFromDoubleRegister(node, src1Reg, cg); } if (src2Reg->getKind() == TR_FPR) { src2Reg = moveFromDoubleRegister(node, src2Reg, cg); } #endif if(!noFPRA) { if((src1Reg->getKind() == TR_FPR) && !cg->canClobberNodesRegister(firstChild, 0)) { TR::Register *tempReg = cg->allocateRegister(TR_FPR); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcpyd, firstChild, tempReg, src1Reg); src1Reg = tempReg; } if((src2Reg->getKind() == TR_FPR) && !cg->canClobberNodesRegister(secondChild, 0)) { TR::Register *tempReg = cg->allocateRegister(TR_FPR); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcpyd, secondChild, tempReg, src2Reg); src2Reg = tempReg; } } if (cg->comp()->target().cpu.isLittleEndian()) { /* Little Endian */ #if defined(__ARM_PCS_VFP) TR::addDependency(dependencies, NULL, TR::RealRegister::gr1, TR_GPR, cg); TR::addDependency(dependencies, NULL, TR::RealRegister::gr0, TR_GPR, cg); dependencies->addPreCondition(src1Reg, TR::RealRegister::fp0); dependencies->addPreCondition(src2Reg, TR::RealRegister::fp1); for (i = 2; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); TR::addDependency(dependencies, NULL, realReg, TR_FPR, cg); } dependencies->addPostCondition(trgReg, TR::RealRegister::fp0); dependencies->addPostCondition(cg->allocateRegister(TR_FPR), TR::RealRegister::fp1);//TODO live register #else dependencies->addPreCondition(src1Reg->getHighOrder(), TR::RealRegister::gr1); dependencies->addPreCondition(src1Reg->getLowOrder(), TR::RealRegister::gr0); TR::addDependency(dependencies, src2Reg->getLowOrder(), TR::RealRegister::gr2, TR_GPR, cg); TR::addDependency(dependencies, src2Reg->getHighOrder(), TR::RealRegister::gr3, TR_GPR, cg); dependencies->addPostCondition(highReg, TR::RealRegister::gr1); dependencies->addPostCondition(lowReg, TR::RealRegister::gr0); #endif } else { /* Big Endian */ #if defined(__ARM_PCS_VFP) TR::addDependency(dependencies, NULL, TR::RealRegister::gr1, TR_GPR, cg); TR::addDependency(dependencies, NULL, TR::RealRegister::gr0, TR_GPR, cg); dependencies->addPreCondition(src1Reg, TR::RealRegister::fp0); dependencies->addPreCondition(src2Reg, TR::RealRegister::fp1); for (i = 2; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); TR::addDependency(dependencies, NULL, realReg, TR_FPR, cg); } dependencies->addPostCondition(trgReg, TR::RealRegister::fp0); dependencies->addPostCondition(cg->allocateRegister(TR_FPR), TR::RealRegister::fp1);//TODO live register #else dependencies->addPreCondition(src1Reg->getHighOrder(), TR::RealRegister::gr0); dependencies->addPreCondition(src1Reg->getLowOrder(), TR::RealRegister::gr1); TR::addDependency(dependencies, src2Reg->getHighOrder(), TR::RealRegister::gr2, TR_GPR, cg); TR::addDependency(dependencies, src2Reg->getLowOrder(), TR::RealRegister::gr3, TR_GPR, cg); dependencies->addPostCondition(highReg, TR::RealRegister::gr0); dependencies->addPostCondition(lowReg, TR::RealRegister::gr1); #endif } dependencies->stopAddingConditions(); generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMdoubleRemainder)->getMethodAddress(), dependencies, cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMdoubleRemainder)); if (noFPRA) { #if defined(__ARM_PCS_VFP) if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); doubleTrgReg = trgReg; } else { doubleTrgReg = moveFromDoubleRegister(node, trgReg, cg); cg->stopUsingRegister(trgReg); } #else doubleTrgReg = trgReg; #endif } else doubleTrgReg = trgReg; cg->decReferenceCount(firstChild); cg->decReferenceCount(secondChild); cg->machine()->setLinkRegisterKilled(true); return doubleTrgReg; } static TR::Register *callFloatRemainderHelper(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = node->getSecondChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Register *src2Reg = cg->evaluate(secondChild); TR::RegisterDependencyConditions *dependencies = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(11, 11, cg->trMemory()); int i; #if defined(__ARM_PCS_VFP) TR::Register *trgReg = cg->allocateSinglePrecisionRegister(); #else TR::Register *trgReg = cg->allocateRegister(TR_GPR); #endif TR::Register *floatTrgReg = NULL; #if defined(__ARM_PCS_VFP) if (src1Reg->getKind() == TR_GPR) { src1Reg = moveToFloatRegister(node, src1Reg, cg); } if (src2Reg->getKind() == TR_GPR) { src2Reg = moveToFloatRegister(node, src2Reg, cg); } #else if (src1Reg->getKind() == TR_FPR) { src1Reg = moveFromFloatRegister(node, src1Reg, cg); } if (src2Reg->getKind() == TR_FPR) { src2Reg = moveFromFloatRegister(node, src2Reg, cg); } #endif #if defined(__ARM_PCS_VFP) if(!noFPRA) { if((src1Reg->getKind() == TR_FPR) && !cg->canClobberNodesRegister(firstChild, 0)) { TR::Register *tempReg = cg->allocateRegister(TR_FPR); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcpys, firstChild, tempReg, src1Reg); src1Reg = tempReg; } if((src2Reg->getKind() == TR_FPR) && !cg->canClobberNodesRegister(secondChild, 0)) { TR::Register *tempReg = cg->allocateRegister(TR_FPR); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcpys, secondChild, tempReg, src2Reg); src2Reg = tempReg; } } TR::addDependency(dependencies, NULL, TR::RealRegister::gr1, TR_GPR, cg); TR::addDependency(dependencies, NULL, TR::RealRegister::gr0, TR_GPR, cg); dependencies->addPreCondition(src1Reg, TR::RealRegister::fp0); dependencies->addPreCondition(src2Reg, TR::RealRegister::fs1); for (i = 1; i < 8; i++) { TR::RealRegister::RegNum realReg = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::fp0 + i); TR::addDependency(dependencies, NULL, realReg, TR_FPR, cg); } dependencies->addPostCondition(trgReg, TR::RealRegister::fp0); #else dependencies->addPreCondition(src1Reg, TR::RealRegister::gr0); dependencies->addPreCondition(src2Reg, TR::RealRegister::gr1); dependencies->addPostCondition(trgReg, TR::RealRegister::gr0); dependencies->addPostCondition(cg->allocateRegister(), TR::RealRegister::gr1);//TODO live register #endif dependencies->stopAddingConditions(); generateImmSymInstruction(cg, TR::InstOpCode::bl, node, (uintptr_t)cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMfloatRemainder)->getMethodAddress(), dependencies, cg->symRefTab()->findOrCreateRuntimeHelper(TR_ARMfloatRemainder)); if (noFPRA) { #if defined(__ARM_PCS_VFP) if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); floatTrgReg = trgReg; } else { floatTrgReg = moveFromFloatRegister(node, trgReg, cg); cg->stopUsingRegister(trgReg); } #else floatTrgReg = trgReg; #endif } else floatTrgReg = trgReg; cg->decReferenceCount(firstChild); cg->decReferenceCount(secondChild); cg->machine()->setLinkRegisterKilled(true); return floatTrgReg; } TR::Register *OMR::ARM::TreeEvaluator::ibits2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *target = NULL; if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 4, cg); if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) traceMsg(cg->comp(), "Result of node %p can stay in FP reg (not exec.).\n", node); target = cg->allocateRegister(); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, target, tempMR); } else { target = cg->allocateSinglePrecisionRegister(); if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->decNodeReferenceCounts(); tempMR = new (cg->trHeapMemory()) TR::MemoryReference(tempReg, 0, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, node, target, tempMR); cg->stopUsingRegister(tempReg); } else generateTrg1MemInstruction(cg, TR::InstOpCode::flds, node, target, tempMR); } tempMR->decNodeReferenceCounts(); } else { TR::Register *srcReg = cg->evaluate(child); if (noFPRA) { target = srcReg; } else { target = moveToFloatRegister(node, srcReg, cg); cg->stopUsingRegister(srcReg); } cg->decReferenceCount(child); } node->setRegister(target); return target; } TR::Register *OMR::ARM::TreeEvaluator::fbits2iEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *target = cg->allocateRegister(); TR_ASSERT(!node->normalizeNanValues(), "Check NAN\n"); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, target, tempMR); tempMR->decNodeReferenceCounts(); } else { TR::Register *srcReg = cg->evaluate(child); if (srcReg->getKind() == TR_FPR) { target = moveFromFloatRegister(node, srcReg, cg); cg->stopUsingRegister(srcReg); } else { target = srcReg; } cg->decReferenceCount(child); } node->setRegister(target); return target; } TR::Register *OMR::ARM::TreeEvaluator::lbits2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::RegisterPair *pairTarget = NULL; TR::Register *target = NULL; TR::Register *lowReg = NULL; TR::Register *highReg = NULL; TR::Compilation *comp = cg->comp(); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *highMem, *lowMem; TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 8, cg); if (noFPRA) { lowReg = cg->allocateRegister(); highReg = cg->allocateRegister(); highMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 0 : 4, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, highReg, highMem); lowMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 4 : 0, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, lowReg, lowMem); highMem->decNodeReferenceCounts(); lowMem->decNodeReferenceCounts(); pairTarget = cg->allocateRegisterPair(lowReg, highReg); node->setRegister(pairTarget); return pairTarget; } else { target = cg->allocateRegister(TR_FPR); highMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, 0, 8, cg); if (highMem->getIndexRegister() && highMem->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, highMem->getBaseRegister(), highMem->getIndexRegister()); highMem->decNodeReferenceCounts(); highMem = new (cg->trHeapMemory()) TR::MemoryReference(tempReg, 0, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::fldd, node, target, highMem); cg->stopUsingRegister(tempReg); } else generateTrg1MemInstruction(cg, TR::InstOpCode::fldd, node, target, highMem); highMem->decNodeReferenceCounts(); node->setRegister(target); return target; } } else { TR::Register *srcReg = cg->evaluate(child); if (noFPRA) { target = srcReg; } else { target = moveToDoubleRegister(node, srcReg, cg); cg->stopUsingRegister(srcReg); } cg->decReferenceCount(child); node->setRegister(target); return target; } } TR::Register *OMR::ARM::TreeEvaluator::dbits2lEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *target = NULL; TR::Register *srcReg = NULL; TR::Register *lowReg = NULL; TR::Register *highReg = NULL; TR::Compilation *comp = cg->comp(); TR_ASSERT(!node->normalizeNanValues(), "Check NAN\n"); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *highMem, *lowMem; TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 8, cg); lowReg = cg->allocateRegister(); highReg = cg->allocateRegister(); highMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 0 : 4, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, highReg, highMem); lowMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 4 : 0, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, lowReg, lowMem); highMem->decNodeReferenceCounts(); lowMem->decNodeReferenceCounts(); target = cg->allocateRegisterPair(lowReg, highReg); tempMR->decNodeReferenceCounts(); // Taken from PPC } else { srcReg = cg->evaluate(child); if (srcReg->getKind() == TR_FPR) { target = moveFromDoubleRegister(node, srcReg, cg); cg->stopUsingRegister(srcReg); } else { target = srcReg; } cg->decReferenceCount(child); } node->setRegister(target); return target; // returns RegisterPair. } TR::Register *OMR::ARM::TreeEvaluator::fconstEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Use PC relative to get to the constant data, loading data at Snippet area is too far // Example: // add r4, r15, #8 (+2 instructions) // flds s0, [r15] (Take advantage of PC+8) // mov r15, r4 (Continue, bypassing the data) // .word 0x3fc00000 (Float value) // fmrs r0, s0 (if result goes back to general register) TR::Register *trgReg = NULL; TR::Register *tempReg = cg->allocateRegister(); TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); float value = node->getFloat(); uint32_t i32 = *(int32_t *)(&value); TR::Compilation *comp = cg->comp(); TR::RealRegister *machineIPReg = cg->machine()->getRealRegister(TR::RealRegister::gr15); TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(2, 2, cg->trMemory()); traceMsg(comp, "In fconstEvaluator %x\n", i32); TR::addDependency(deps, tempReg, TR::RealRegister::NoReg, TR_GPR, cg); if(!noFPRA) { TR::addDependency(deps, floatTrgReg, TR::RealRegister::NoReg, TR_FPR, cg); } deps->stopAddingConditions(); generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, tempReg, machineIPReg, 8, 0); TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(machineIPReg, NULL, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, node, floatTrgReg, tempMR); generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, machineIPReg, tempReg); //cg->stopUsingRegister(tempReg); // Place the constant generateImmInstruction(cg, TR::InstOpCode::dd, node, i32); //armCG(cg)->findOrCreateFloatConstant(&value, TR::Float, cursor); if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); trgReg = floatTrgReg; } else { trgReg = moveFromFloatRegister(node, floatTrgReg, cg); cg->stopUsingRegister(floatTrgReg); } } else trgReg = floatTrgReg; TR::LabelSymbol *fenceLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg); generateLabelInstruction(cg, TR::InstOpCode::label, node, fenceLabel, deps); cg->stopUsingRegister(tempReg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::dconstEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Use PC relative to get to the constant data, loading data at Snippet area is too far // Example: // add r4, r15, #12 (Target +3 instructions) // fldd d5, [r15] (Take advantage of PC+8) // mov r15, r4 (Continue, bypassing the data) // .word 0x33333333 (lower 32 for little endian) // .word 0x40033333 (upper 32 for little endian) // fmrrd r0, r1, d5 (if result goes back to general register) TR::Register *trgReg = NULL; TR::Register *tempReg = cg->allocateRegister(); TR::Register *doubleTrgReg = cg->allocateRegister(TR_FPR); double value = node->getDouble(); uint64_t i64 = (*(int64_t *)&value); TR::Compilation *comp = cg->comp(); TR::RealRegister *machineIPReg = cg->machine()->getRealRegister(TR::RealRegister::gr15); TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(2, 2, cg->trMemory()); traceMsg(comp, "In dconstEvaluator %x\n", i64); TR::addDependency(deps, tempReg, TR::RealRegister::NoReg, TR_GPR, cg); if(!noFPRA) { TR::addDependency(deps, doubleTrgReg, TR::RealRegister::NoReg, TR_FPR, cg); } deps->stopAddingConditions(); generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, tempReg, machineIPReg, 12, 0); TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(machineIPReg, NULL, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::fldd, node, doubleTrgReg, tempMR); generateTrg1Src1Instruction(cg, TR::InstOpCode::mov, node, machineIPReg, tempReg); //cg->stopUsingRegister(tempReg); // Place the constant //armCG(cg)->findOrCreateFloatConstant(&value, TR::Double, high, low); if (cg->comp()->target().cpu.isLittleEndian()) { generateImmInstruction(cg, TR::InstOpCode::dd, node, (int32_t)i64); generateImmInstruction(cg, TR::InstOpCode::dd, node, (int32_t)((i64>>32) & 0xffffffff)); } else { generateImmInstruction(cg, TR::InstOpCode::dd, node, (int32_t)((i64>>32) & 0xffffffff)); generateImmInstruction(cg, TR::InstOpCode::dd, node, (int32_t)i64); } if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(comp, "Result of node %p can stay in FP reg.\n", node); trgReg = doubleTrgReg; } else { trgReg = moveFromDoubleRegister(node, doubleTrgReg, cg); cg->stopUsingRegister(doubleTrgReg); } } else trgReg = doubleTrgReg; TR::LabelSymbol *fenceLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg); generateLabelInstruction(cg, TR::InstOpCode::label, node, fenceLabel, deps); cg->stopUsingRegister(tempReg); node->setRegister(trgReg); return trgReg; } // also handles TR::floadi TR::Register *OMR::ARM::TreeEvaluator::floadEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = NULL; //#define STAYINFP #ifdef STAYINFP TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); #endif TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 4, cg); #ifdef STAYINFP if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->decNodeReferenceCounts(); tempMR = new (cg->trHeapMemory()) TR::MemoryReference(tempReg, 0, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, node, floatTrgReg, tempMR); cg->stopUsingRegister(tempReg); } else generateTrg1MemInstruction(cg, TR::InstOpCode::flds, node, floatTrgReg, tempMR); #endif if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg in fload.\n", node); // This seem to break things.. trgReg = floatTrgReg; #ifdef STAYINFP trgReg = floatTrgReg; #else // Load directly to a general register trgReg = cg->allocateRegister(); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, trgReg, tempMR); #endif } else { // Load directly to a general register trgReg = cg->allocateRegister(); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, trgReg, tempMR); } } else { TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->decNodeReferenceCounts(); tempMR = new (cg->trHeapMemory()) TR::MemoryReference(tempReg, 0, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, node, floatTrgReg, tempMR); cg->stopUsingRegister(tempReg); } else generateTrg1MemInstruction(cg, TR::InstOpCode::flds, node, floatTrgReg, tempMR); trgReg = floatTrgReg; } if (node->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor) { generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node); } tempMR->decNodeReferenceCounts(); node->setRegister(trgReg); return trgReg; } // also handles TR::dloadi TR::Register *OMR::ARM::TreeEvaluator::dloadEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = NULL; TR::Register *doubleTrgReg = cg->allocateRegister(TR_FPR); TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 8, cg); if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->decNodeReferenceCounts(); tempMR = new (cg->trHeapMemory()) TR::MemoryReference(tempReg, 0, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::fldd, node, doubleTrgReg, tempMR); cg->stopUsingRegister(tempReg); } else generateTrg1MemInstruction(cg, TR::InstOpCode::fldd, node, doubleTrgReg, tempMR); if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg in dload.\n", node); trgReg = doubleTrgReg; } else { trgReg = moveFromDoubleRegister(node, doubleTrgReg, cg); cg->stopUsingRegister(doubleTrgReg); } } else { trgReg = doubleTrgReg; } if (node->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor) { generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node); } tempMR->decNodeReferenceCounts(); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::fstoreEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *sourceReg = cg->evaluate(firstChild); TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 4, cg); if (node->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor) { generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node); } if (noFPRA) { if (sourceReg->getKind() == TR_GPR) { // sourceReg is in a general register generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, sourceReg); } else if (sourceReg->getKind() == TR_FPR) { if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); tempMR->setBaseNode(node); generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); } } else { if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); tempMR->setBaseNode(node); generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); } cg->decReferenceCount(firstChild); tempMR->decNodeReferenceCounts(); return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dstoreEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *sourceReg = cg->evaluate(firstChild); bool isUnresolved = node->getSymbolReference()->isUnresolved(); if (node->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor) { generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node); } if (noFPRA) { if (sourceReg->getKind() == TR_GPR) { // sourceReg is in general registers, mimic a lstore TR::MemoryReference *lowMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 4, cg); TR::MemoryReference *highMR = new (cg->trHeapMemory()) TR::MemoryReference(*lowMR, 4, 4, cg); if (cg->comp()->target().cpu.isBigEndian()) { generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, lowMR, sourceReg->getHighOrder()); generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, highMR, sourceReg->getLowOrder()); } else { generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, lowMR, sourceReg->getLowOrder()); generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, highMR, sourceReg->getHighOrder()); } } else if (sourceReg->getKind() == TR_FPR) { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 8, cg); if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); tempMR->setBaseNode(node); generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); tempMR->decNodeReferenceCounts(); } else TR_ASSERT(0, "Unknown register type\n"); } else { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 8, cg); if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); tempMR->setBaseNode(node); generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); tempMR->decNodeReferenceCounts(); } cg->decReferenceCount(firstChild); return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fstoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *secondChild = node->getSecondChild(); TR::Register *sourceReg = cg->evaluate(secondChild); TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 4, cg); if (node->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor) { generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node); } if (noFPRA) { if (sourceReg->getKind() == TR_GPR) { // sourceReg is in a general register generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, tempMR, sourceReg); } else if (sourceReg->getKind() == TR_FPR) { if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); //tempMR->setBaseNode(node); generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); } } else { if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fsts, node, tempMR, sourceReg); } cg->decReferenceCount(secondChild); tempMR->decNodeReferenceCounts(); return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dstoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *secondChild = node->getSecondChild(); TR::Register *sourceReg = cg->evaluate(secondChild); if (node->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP() && cg->comp()->target().cpu.id() != TR_DefaultARMProcessor) { generateInstruction(cg, (cg->comp()->target().cpu.id() == TR_ARMv6) ? TR::InstOpCode::dmb_v6 : TR::InstOpCode::dmb, node); } if (noFPRA) { if (sourceReg->getKind() == TR_GPR) { // sourceReg is in general registers, mimic a lstore TR::MemoryReference *lowMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 4, cg); TR::MemoryReference *highMR = new (cg->trHeapMemory()) TR::MemoryReference(*lowMR, 4, 4, cg); if (cg->comp()->target().cpu.isBigEndian()) { generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, lowMR, sourceReg->getHighOrder()); generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, highMR, sourceReg->getLowOrder()); } else { generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, lowMR, sourceReg->getLowOrder()); generateMemSrc1Instruction(cg, TR::InstOpCode::str, node, highMR, sourceReg->getHighOrder()); } } else if (sourceReg->getKind() == TR_FPR) { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 8, cg); if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); tempMR->decNodeReferenceCounts(); } else TR_ASSERT(0, "Unknown register type\n"); } else { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(node, 8, cg); if (tempMR->getIndexRegister() && tempMR->getBaseRegister()) { TR::Register *tempReg = cg->allocateRegister(); generateTrg1Src2Instruction(cg, TR::InstOpCode::add, node, tempReg, tempMR->getBaseRegister(), tempMR->getIndexRegister()); tempMR->setIndexRegister(NULL); tempMR->setIndexNode(NULL); tempMR->setBaseRegister(tempReg); generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); cg->stopUsingRegister(tempReg); } else generateMemSrc1Instruction(cg, TR::InstOpCode::fstd, node, tempMR, sourceReg); tempMR->decNodeReferenceCounts(); } cg->decReferenceCount(secondChild); return NULL; } TR::Register *OMR::ARM::TreeEvaluator::freturnEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // SOFT-ABI uses general registers to return floats TR::Register *returnRegister = cg->evaluate(node->getFirstChild()); TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory()); if (returnRegister->getKind() == TR_GPR) { TR::addDependency(deps, returnRegister, cg->getProperties().getIntegerReturnRegister(), TR_GPR, cg); } else if (returnRegister->getKind() == TR_FPR) { TR::Register *temp = moveFromFloatRegister(node, returnRegister, cg); TR::addDependency(deps, temp, cg->getProperties().getIntegerReturnRegister(), TR_GPR, cg); } else TR_ASSERT(0, "Unknown register type\n"); generateAdminInstruction(cg, TR::InstOpCode::retn, node, deps); cg->comp()->setReturnInfo(TR_FloatReturn); return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dreturnEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *returnRegister = cg->evaluate(node->getFirstChild()); TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(2, 2, cg->trMemory()); if (returnRegister->getKind() == TR_GPR) { TR::addDependency(deps, returnRegister->getLowOrder(), cg->getProperties().getLongLowReturnRegister(), TR_GPR, cg); TR::addDependency(deps, returnRegister->getHighOrder(), cg->getProperties().getLongHighReturnRegister(), TR_GPR, cg); } else if (returnRegister->getKind() == TR_FPR) { TR::Register *temp = moveFromDoubleRegister(node, returnRegister, cg); TR::addDependency(deps, temp->getLowOrder(), cg->getProperties().getLongLowReturnRegister(), TR_GPR, cg); TR::addDependency(deps, temp->getHighOrder(), cg->getProperties().getLongHighReturnRegister(), TR_GPR, cg); } else TR_ASSERT(0, "Unknown register type\n"); generateAdminInstruction(cg, TR::InstOpCode::retn, node, deps); cg->comp()->setReturnInfo(TR_DoubleReturn); return NULL; } static bool isFPStrictMul(TR::Node *node, TR::Compilation * comp) { if(!node->getOpCode().isMul() || !node->isFPStrictCompliant() || node->getRegister()) return false; if( node->getReferenceCount() < 2 && node->getRegister() == NULL) return true; node->setIsFPStrictCompliant(false);// need to set this otherwise children get incorrectly bumped return false; } /** Generate a fused multiply add from the tree (A * B) + C, where addNode is the + node * and mulNode the * subtree. Not supporting noFPRA at this time */ static TR::Register *generateFusedMultiplyAdd(TR::Node *addNode, TR::InstOpCode::Mnemonic OpCode, TR::CodeGenerator *cg) { TR::Node *mulNode = addNode->getFirstChild(); TR::Node *addChild = addNode->getSecondChild(); if (!isFPStrictMul(mulNode, cg->comp())) { addChild = addNode->getFirstChild(); mulNode = addNode->getSecondChild(); } TR_ASSERT(mulNode->getReferenceCount() < 2,"Mul node 0x%p reference count %d >= 2\n",mulNode,mulNode->getReferenceCount()); TR_ASSERT(mulNode->getOpCode().isMul(),"Unexpected op!=mul %p\n",mulNode); TR_ASSERT(mulNode->isFPStrictCompliant(),"mul node %p is not fpStrict Compliant\n",mulNode); TR::Register *source1Register = cg->evaluate(mulNode->getFirstChild()); TR::Register *source2Register = cg->evaluate(mulNode->getSecondChild()); TR::Register *source3Register = cg->evaluate(addChild); // Result is in the put back to source3Register TR::Register *trgRegister = source3Register; if (addNode->getDataType() == TR::Float) { if (noFPRA) { TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); generateTrg1Src2Instruction(cg, OpCode, addNode, floatTrgReg, moveToFloatRegister(addNode, source1Register, cg), moveToFloatRegister(addNode, source2Register, cg)); generateTrg1Src1Instruction(cg, TR::InstOpCode::fmrs, addNode, trgRegister, floatTrgReg); cg->stopUsingRegister(floatTrgReg); } else { generateTrg1Src2Instruction(cg, OpCode, addNode, trgRegister, source1Register, source2Register); } } else { // TR::Double if (noFPRA) { TR::Register *doubleTrgReg = cg->allocateRegister(TR_FPR); generateTrg1Src2Instruction(cg, OpCode, addNode, doubleTrgReg, moveToDoubleRegister(addNode, source1Register, cg), moveToDoubleRegister(addNode, source2Register, cg)); generateTrg2Src1Instruction(cg, TR::InstOpCode::fmrrd, addNode, trgRegister->getLowOrder(), trgRegister->getHighOrder(), doubleTrgReg); cg->stopUsingRegister(doubleTrgReg); } else { generateTrg1Src2Instruction(cg, OpCode, addNode, trgRegister, source1Register, source2Register); } } addNode->setRegister(trgRegister); cg->decReferenceCount(mulNode->getFirstChild()); cg->decReferenceCount(mulNode->getSecondChild()); cg->decReferenceCount(mulNode); // don't forget this guy! //cg->decReferenceCount(addChild); return trgRegister; } TR::Register *OMR::ARM::TreeEvaluator::faddEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // TODO: Check conditions to use fmacs if possible TR::Compilation *comp = cg->comp(); TR::Register *result = NULL; if (((isFPStrictMul(node->getFirstChild(), comp) && (node->getSecondChild()->getReferenceCount() == 1)) || (isFPStrictMul(node->getSecondChild(), comp) && (node->getFirstChild()->getReferenceCount() == 1))) && performTransformation(comp, "O^O Changing [%p] to fmacs\n", node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fmacs, cg); } else { result = singlePrecisionEvaluator(node, TR::InstOpCode::fadds, cg); } return result; } TR::Register *OMR::ARM::TreeEvaluator::daddEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // TODO: Check conditions to use fmacd if possible TR::Register *result = NULL; TR::Compilation *comp = cg->comp(); if (((isFPStrictMul(node->getFirstChild(), comp) && (node->getSecondChild()->getReferenceCount() == 1)) || (isFPStrictMul(node->getSecondChild(), comp) && (node->getFirstChild()->getReferenceCount() == 1))) && performTransformation(comp, "O^O Changing [%p] to fmacd\n", node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fmacd, cg); } else { result = doublePrecisionEvaluator(node, TR::InstOpCode::faddd, cg); } return result; } TR::Register *OMR::ARM::TreeEvaluator::dsubEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // TODO: Check conditions to use fmscd if possible TR::Compilation *comp = cg->comp(); TR::Register *result = NULL; if (isFPStrictMul(node->getFirstChild(), comp) && (node->getSecondChild()->getReferenceCount() == 1) && performTransformation(comp, "O^O Changing [%p] to fmscd\n",node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fmscd, cg); } else if (isFPStrictMul(node->getSecondChild(), comp) && (node->getFirstChild()->getReferenceCount() == 1) && performTransformation(comp, "O^O Changing [%p] to fnmacd\n",node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fnmacd, cg); } else { result = doublePrecisionEvaluator(node, TR::InstOpCode::fsubd, cg); } return result; } TR::Register *OMR::ARM::TreeEvaluator::fsubEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // TODO: Check conditions to use fmscs if possible TR::Compilation *comp = cg->comp(); TR::Register *result = NULL; if (isFPStrictMul(node->getFirstChild(), comp) && (node->getSecondChild()->getReferenceCount() == 1) && performTransformation(comp, "O^O Changing [%p] to fmscs\n",node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fmscs, cg); } else if (isFPStrictMul(node->getSecondChild(), comp) && (node->getFirstChild()->getReferenceCount() == 1) && performTransformation(comp, "O^O Changing [%p] to fnmacs\n",node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fnmacs, cg); } else { result = singlePrecisionEvaluator(node, TR::InstOpCode::fsubs, cg); } return result; } TR::Register *OMR::ARM::TreeEvaluator::fmulEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return singlePrecisionEvaluator(node, TR::InstOpCode::fmuls, cg); } TR::Register *OMR::ARM::TreeEvaluator::dmulEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return doublePrecisionEvaluator(node, TR::InstOpCode::fmuld, cg); } TR::Register *OMR::ARM::TreeEvaluator::fdivEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return singlePrecisionEvaluator(node, TR::InstOpCode::fdivs, cg); } TR::Register *OMR::ARM::TreeEvaluator::ddivEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return doublePrecisionEvaluator(node, TR::InstOpCode::fdivd, cg); } TR::Register *OMR::ARM::TreeEvaluator::fremEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = callFloatRemainderHelper(node, cg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::dremEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = callDoubleRemainderHelper(node, cg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::fabsEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return singlePrecisionEvaluator(node, TR::InstOpCode::fabss, cg); } TR::Register *OMR::ARM::TreeEvaluator::dabsEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return doublePrecisionEvaluator(node, TR::InstOpCode::fabsd, cg); } TR::Register *OMR::ARM::TreeEvaluator::fnegEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // TODO: Check tree for possibile combinations TR::Register *result = NULL; TR::Node *firstChild = node->getFirstChild(); bool isAdd = firstChild->getOpCode().isAdd(); TR::Compilation *comp = cg->comp(); if (firstChild->getReferenceCount() < 2 && !firstChild->getRegister() && isAdd) { // fneg(node) -> fadd(firstChild) -> a multiply in one of the children if (((isFPStrictMul(firstChild->getFirstChild(), comp) && firstChild->getSecondChild()->getReferenceCount() == 1) || (isFPStrictMul(firstChild->getSecondChild(), comp) && firstChild->getFirstChild()->getReferenceCount() == 1)) && performTransformation(comp, "O^O Changing [%p] to fnmscs\n", node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fnmscs, cg); firstChild->unsetRegister(); //unset as the first child isn't the result node } else { result = singlePrecisionEvaluator(node, TR::InstOpCode::fnegs, cg); } } else if (isFPStrictMul(firstChild, comp) && firstChild->getReferenceCount() < 2 && !firstChild->getRegister() && performTransformation(comp, "O^O Changing [%p] to fnmuls\n", node)) { // fneg(node) -> fmul(firstChild) TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); TR::Register *src1Register = cg->evaluate(firstChild->getFirstChild()); TR::Register *src2Register = cg->evaluate(firstChild->getSecondChild()); if (noFPRA) { generateTrg1Src2Instruction(cg, TR::InstOpCode::fnmuls, node, floatTrgReg, moveToFloatRegister(node, src1Register, cg), moveToFloatRegister(node, src2Register, cg)); result = moveFromFloatRegister(node, floatTrgReg, cg); cg->stopUsingRegister(floatTrgReg); } else { generateTrg1Src2Instruction(cg, TR::InstOpCode::fnmuls, node, floatTrgReg, src1Register, src2Register); result = floatTrgReg; } cg->decReferenceCount(firstChild); } else { result = singlePrecisionEvaluator(node, TR::InstOpCode::fnegs, cg); } node->setRegister(result); return result; } TR::Register *OMR::ARM::TreeEvaluator::dnegEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // TODO: Check tree for possible combinations TR::Register *result = NULL; TR::Node *firstChild = node->getFirstChild(); bool isAdd = firstChild->getOpCode().isAdd(); TR::Compilation *comp = cg->comp(); if (firstChild->getReferenceCount() < 2 && !firstChild->getRegister() && isAdd) { // dneg(node) -> dadd(firstChild) -> a multiply in one of the children if (((isFPStrictMul(firstChild->getFirstChild(), comp) && firstChild->getSecondChild()->getReferenceCount() == 1) || (isFPStrictMul(firstChild->getSecondChild(), comp) && firstChild->getFirstChild()->getReferenceCount() == 1)) && performTransformation(comp, "O^O Changing [%p] to fnmscd\n", node)) { result = generateFusedMultiplyAdd(node, TR::InstOpCode::fnmscd, cg); firstChild->unsetRegister(); //unset as the first child isn't the result node } else { result = doublePrecisionEvaluator(node, TR::InstOpCode::fnegd, cg); } } else if (isFPStrictMul(firstChild, comp) && firstChild->getReferenceCount() < 2 && !firstChild->getRegister() && performTransformation(comp, "O^O Changing [%p] to fnmuld\n", node)) { // fneg(node) -> fmul(firstChild) TR::Register *doubleTrgReg = cg->allocateRegister(TR_FPR); TR::Register *src1Register = cg->evaluate(firstChild->getFirstChild()); TR::Register *src2Register = cg->evaluate(firstChild->getSecondChild()); if (noFPRA) { generateTrg1Src2Instruction(cg, TR::InstOpCode::fnmuld, node, doubleTrgReg, moveToDoubleRegister(node, src1Register, cg), moveToDoubleRegister(node, src2Register, cg)); result = moveFromDoubleRegister(node, doubleTrgReg, cg); cg->stopUsingRegister(doubleTrgReg); } else { generateTrg1Src2Instruction(cg, TR::InstOpCode::fnmuld, node, doubleTrgReg, src1Register, src2Register); result = doubleTrgReg; } cg->decReferenceCount(firstChild); } else { result = doublePrecisionEvaluator(node, TR::InstOpCode::fnegd, cg); } node->setRegister(result); return result; } TR::Register *OMR::ARM::TreeEvaluator::i2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Support iu2f, b2f, s2f and su2f TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = NULL; TR::Register *trgReg = NULL; TR::InstOpCode::Mnemonic opcode = (node->getOpCodeValue() == TR::iu2f) ? TR::InstOpCode::fuitos : TR::InstOpCode::fsitos; if (firstChild->getReferenceCount() == 1 && firstChild->getRegister() == NULL && (firstChild->getOpCodeValue() == TR::iload || firstChild->getOpCodeValue() == TR::iloadi) && (firstChild->getNumChildren() > 0) && (firstChild->getFirstChild()->getNumChildren() == 1) && !(firstChild->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP())) { // Coming from memory, last use. Use flds to save the move TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(firstChild, 4, cg); TR::Register *tempReg = cg->allocateSinglePrecisionRegister(); TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, firstChild, tempReg, tempMR); generateTrg1Src1Instruction(cg, opcode, node, floatTrgReg, tempReg); if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); trgReg = floatTrgReg; } else { trgReg = moveFromFloatRegister(node, floatTrgReg, cg); cg->stopUsingRegister(floatTrgReg); } } else trgReg = floatTrgReg; cg->stopUsingRegister(tempReg); node->setRegister(trgReg); cg->decReferenceCount(firstChild); } else { // GPR -> FP -> Convert trgReg = singlePrecisionEvaluator(node, opcode, cg); } return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::i2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Supports iu2d, b2d, s2d, su2d TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = NULL; TR::Register *trgReg = NULL; TR::Register *tempReg = cg->allocateSinglePrecisionRegister(); TR::InstOpCode::Mnemonic opcode = (node->getOpCodeValue() != TR::iu2d && node->getOpCodeValue() != TR::su2d) ? TR::InstOpCode::fsitod : TR::InstOpCode::fuitod; // D[t], S[s] if (firstChild->getReferenceCount() == 1 && firstChild->getRegister() == NULL && (firstChild->getOpCodeValue() == TR::iload || firstChild->getOpCodeValue() == TR::iloadi) && (firstChild->getNumChildren() > 0) && (firstChild->getFirstChild()->getNumChildren() == 1) && !(firstChild->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP())) { // Coming from memory, last use TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(firstChild, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, firstChild, tempReg, tempMR); tempMR->decNodeReferenceCounts(); } else { // GPR -> FP -> Convert src1Reg = cg->evaluate(firstChild); // int tempReg = moveToFloatRegister(node, src1Reg, cg); // fmsr cg->decReferenceCount(firstChild); } TR::Register *doubleTrgReg = cg->allocateRegister(TR_FPR); generateTrg1Src1Instruction(cg, opcode, node, doubleTrgReg, tempReg); // The conversion.. source is float, result is double if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); trgReg = doubleTrgReg; } else { trgReg = moveFromDoubleRegister(node, doubleTrgReg, cg); cg->stopUsingRegister(doubleTrgReg); } } else { trgReg = doubleTrgReg; } cg->stopUsingRegister(tempReg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::l2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = callLong2FloatHelper(node, cg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::l2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = callLong2DoubleHelper(node, cg); node->setRegister(trgReg); return trgReg; } // f2s handled by d2sEvaluator // f2c handled by d2cEvaluator // f2b handled by d2bEvaluator // f2l handled by d2lEvaluator TR::Register *OMR::ARM::TreeEvaluator::f2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = NULL; TR::Register *trgReg = NULL; // NEW TR::Register *doubleTrgReg = cg->allocateRegister(TR_FPR); if (firstChild->getReferenceCount() == 1 && firstChild->getRegister() == NULL && (firstChild->getOpCodeValue() == TR::fload || firstChild->getOpCodeValue() == TR::floadi) && (firstChild->getNumChildren() > 0) && (firstChild->getFirstChild()->getNumChildren() == 1) && !(firstChild->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP())) { // Coming from memory, last use TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(firstChild, 4, cg); TR::Register *tempReg = cg->allocateSinglePrecisionRegister(); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, firstChild, tempReg, tempMR); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcvtds, node, doubleTrgReg, tempReg); tempMR->decNodeReferenceCounts(); cg->stopUsingRegister(tempReg); } else { src1Reg = cg->evaluate(firstChild); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcvtds, node, doubleTrgReg, moveToFloatRegister(node, src1Reg, cg)); cg->decReferenceCount(firstChild); } if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); trgReg = doubleTrgReg; } else { trgReg = moveFromDoubleRegister(node, doubleTrgReg, cg); cg->stopUsingRegister(doubleTrgReg); } } else { trgReg = doubleTrgReg; } node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::f2iEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Supports f2iu TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = NULL; TR::Register *trgReg = NULL; TR::InstOpCode::Mnemonic opcode = (node->getOpCodeValue() == TR::f2i) ? TR::InstOpCode::ftosizs : TR::InstOpCode::ftouizs; TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); if (firstChild->getReferenceCount() == 1 && firstChild->getRegister() == NULL && (firstChild->getOpCodeValue() == TR::fload || firstChild->getOpCodeValue() == TR::floadi) && (firstChild->getNumChildren() > 0) && (firstChild->getFirstChild()->getNumChildren() == 1) && !(firstChild->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP())) { // Coming from memory, last use TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(firstChild, 4, cg); TR::Register *tempReg = cg->allocateSinglePrecisionRegister(); generateTrg1MemInstruction(cg, TR::InstOpCode::flds, firstChild, tempReg, tempMR); generateTrg1Src1Instruction(cg, opcode, node, floatTrgReg, tempReg); tempMR->decNodeReferenceCounts(); cg->stopUsingRegister(tempReg); } else { src1Reg = cg->evaluate(firstChild); generateTrg1Src1Instruction(cg, opcode, node, floatTrgReg, moveToFloatRegister(node, src1Reg, cg)); cg->decReferenceCount(firstChild); } // Integer result trgReg = moveFromFloatRegister(node, floatTrgReg, cg); cg->stopUsingRegister(floatTrgReg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::d2iEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Supports d2iu TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = NULL; TR::Register *trgReg = NULL; TR::InstOpCode::Mnemonic opcode = (node->getOpCodeValue() == TR::d2i) ? TR::InstOpCode::ftosizd : TR::InstOpCode::ftouizd; TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); if (firstChild->getReferenceCount() == 1 && firstChild->getRegister() == NULL && (firstChild->getOpCodeValue() == TR::dload || firstChild->getOpCodeValue() == TR::dloadi) && (firstChild->getNumChildren() > 0) && (firstChild->getFirstChild()->getNumChildren() == 1) && !(firstChild->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP())) { // Coming from memory, last use TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(firstChild, 4, cg); TR::Register *tempReg = cg->allocateRegister(TR_FPR); // double generateTrg1MemInstruction(cg, TR::InstOpCode::fldd, firstChild, tempReg, tempMR); generateTrg1Src1Instruction(cg, opcode, node, floatTrgReg, tempReg); tempMR->decNodeReferenceCounts(); cg->stopUsingRegister(tempReg); } else { src1Reg = cg->evaluate(firstChild); generateTrg1Src1Instruction(cg, opcode, node, floatTrgReg, moveToDoubleRegister(node, src1Reg, cg)); cg->decReferenceCount(firstChild); } // Integer result trgReg = moveFromFloatRegister(node, floatTrgReg, cg); cg->stopUsingRegister(floatTrgReg); node->setRegister(trgReg); return trgReg; } // also handles f2c TR::Register *OMR::ARM::TreeEvaluator::d2cEvaluator(TR::Node *node, TR::CodeGenerator *cg) { diagnostic("Not expecting d2c/f2c\n"); return NULL; } // also handles f2s TR::Register *OMR::ARM::TreeEvaluator::d2sEvaluator(TR::Node *node, TR::CodeGenerator *cg) { diagnostic("Not expecting d2s/f2s\n"); return NULL; } // also handles f2b TR::Register *OMR::ARM::TreeEvaluator::d2bEvaluator(TR::Node *node, TR::CodeGenerator *cg) { diagnostic("Not expecting d2b/f2b\n"); return NULL; } TR::Register *OMR::ARM::TreeEvaluator::f2lEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = callFloat2LongHelper(node, cg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::d2lEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Register *trgReg = callDouble2LongHelper(node, cg); node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::d2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = NULL; TR::Register *trgReg = NULL; TR::Register *floatTrgReg = cg->allocateSinglePrecisionRegister(); // NEW if (firstChild->getReferenceCount() == 1 && firstChild->getRegister() == NULL && (firstChild->getOpCodeValue() == TR::dload || firstChild->getOpCodeValue() == TR::dloadi) && (firstChild->getNumChildren() > 0) && (firstChild->getFirstChild()->getNumChildren() == 1) && !(firstChild->getSymbolReference()->getSymbol()->isAtLeastOrStrongerThanAcquireRelease() && cg->comp()->target().isSMP())) { // Coming from memory, last use TR::Register *tempReg = cg->allocateRegister(TR_FPR); TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(firstChild, 8, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::fldd, firstChild, tempReg, tempMR); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcvtsd, node, floatTrgReg, tempReg); tempMR->decNodeReferenceCounts(); cg->stopUsingRegister(tempReg); } else { src1Reg = cg->evaluate(firstChild); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcvtsd, node, floatTrgReg, moveToDoubleRegister(node, src1Reg, cg)); cg->decReferenceCount(firstChild); } if (noFPRA) { if (resultCanStayInFloatRegister(cg->getCurrentEvaluationTreeTop()->getNode(), node)) { traceMsg(cg->comp(), "Result of node %p can stay in FP reg.\n", node); trgReg = floatTrgReg; } else { trgReg = moveFromFloatRegister(node, floatTrgReg, cg); cg->stopUsingRegister(floatTrgReg); } } else { trgReg = floatTrgReg; } node->setRegister(trgReg); return trgReg; } static void ifFloatEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic opCode, TR_ARMConditionCode cond, TR::CodeGenerator *cg, bool isDouble, bool unordered) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = node->getSecondChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Register *src2Reg = cg->evaluate(secondChild); TR::LabelSymbol *label = node->getBranchDestination()->getNode()->getLabel(); TR::RegisterDependencyConditions *deps = NULL; if (noFPRA) { if (isDouble) { generateSrc2Instruction(cg, opCode, node, moveToDoubleRegister(node, src1Reg, cg), moveToDoubleRegister(node, src2Reg, cg)); } else { generateSrc2Instruction(cg, opCode, node, moveToFloatRegister(node, src1Reg, cg), moveToFloatRegister(node, src2Reg, cg)); } } else { generateSrc2Instruction(cg, opCode, node, src1Reg, src2Reg); } // Move the FPSCR flags back to the APSR generateInstruction(cg, TR::InstOpCode::fmstat, node); cg->decReferenceCount(firstChild); cg->decReferenceCount(secondChild); if (node->getNumChildren() == 3) { TR::Node *thirdChild = node->getChild(2); cg->evaluate(thirdChild); deps = generateRegisterDependencyConditions(cg, thirdChild, 0); cg->decReferenceCount(thirdChild); } if (deps) { generateConditionalBranchInstruction(cg, node, cond, label, deps); if (unordered) generateConditionalBranchInstruction(cg, node, ARMConditionCodeVS, label, deps); } else { generateConditionalBranchInstruction(cg, node, cond, label); if (unordered) generateConditionalBranchInstruction(cg, node, ARMConditionCodeVS, label); } } static TR::Register *setboolFloatEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic opCode, TR_ARMConditionCode cond, TR::CodeGenerator *cg, bool isDouble, bool unordered) { TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = node->getSecondChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Register *src2Reg = cg->evaluate(secondChild); TR::Register *trgReg = cg->allocateRegister(); if (noFPRA) { if (isDouble) { generateSrc2Instruction(cg, opCode, node, moveToDoubleRegister(node, src1Reg, cg), moveToDoubleRegister(node, src2Reg, cg)); } else { generateSrc2Instruction(cg, opCode, node, moveToFloatRegister(node, src1Reg, cg), moveToFloatRegister(node, src2Reg, cg)); } } else { generateSrc2Instruction(cg, opCode, node, src1Reg, src2Reg); } // Move the FPSCR flags back to the APSR generateInstruction(cg, TR::InstOpCode::fmstat, node); cg->decReferenceCount(firstChild); cg->decReferenceCount(secondChild); // Initialize the 0 result first generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, trgReg, 0, 0); TR::Instruction *cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, trgReg, 1, 0); cursor->setConditionCode(cond); if (unordered) { cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, trgReg, 1, 0, cursor); cursor->setConditionCode(ARMConditionCodeVS); } node->setRegister(trgReg); return trgReg; } // also handles TR::iffcmpeq, TR::iffcmpequ, TR::ifdcmpequ TR::Register *OMR::ARM::TreeEvaluator::ifdcmpeqEvaluator(TR::Node *node, TR::CodeGenerator *cg) { bool isDouble = (node->getOpCodeValue() == TR::ifdcmpeq || node->getOpCodeValue() == TR::ifdcmpequ); bool unordered = (node->getOpCodeValue() == TR::iffcmpequ || node->getOpCodeValue() == TR::ifdcmpequ); ifFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, ARMConditionCodeEQ, cg, isDouble, unordered); return NULL; } // also handles TR::iffcmpne, TR::iffcmpneu, TR::ifdcmpneu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpneEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeNE may imply unordered, but looks like it is not used in common code bool isDouble = (node->getOpCodeValue() == TR::ifdcmpne || node->getOpCodeValue() == TR::ifdcmpneu); ifFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, ARMConditionCodeNE, cg, isDouble, false); return NULL; } // also handles TR::iffcmplt, TR::iffcmpltu, TR::ifdcmpltu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpltEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeCC is for LT and ARMConditionCodeLT is for LTU bool isDouble = (node->getOpCodeValue() == TR::ifdcmplt || node->getOpCodeValue() == TR::ifdcmpltu); bool unordered = (node->getOpCodeValue() == TR::iffcmpltu || node->getOpCodeValue() == TR::ifdcmpltu); ifFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeLT : ARMConditionCodeCC, cg, isDouble, false); return NULL; } // also handles TR::iffcmpge, TR::iffcmpgeu, TR::ifdcmpgeu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpgeEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeGE is for GE and ARMConditionCodeCS is for GEU bool isDouble = (node->getOpCodeValue() == TR::ifdcmpge || node->getOpCodeValue() == TR::ifdcmpgeu); bool unordered = (node->getOpCodeValue() == TR::iffcmpgeu || node->getOpCodeValue() == TR::ifdcmpgeu); ifFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeCS : ARMConditionCodeGE, cg, isDouble, false); return NULL; } // also handles TR::iffcmpgt, TR::iffcmpgtu, TR::ifdcmpgtu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpgtEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeGT is for GT and ARMConditionCodeHI is for GTU bool isDouble = (node->getOpCodeValue() == TR::ifdcmpgt || node->getOpCodeValue() == TR::ifdcmpgtu); bool unordered = (node->getOpCodeValue() == TR::iffcmpgtu || node->getOpCodeValue() == TR::ifdcmpgtu); ifFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeHI : ARMConditionCodeGT, cg, isDouble, false); return NULL; } // also handles TR::iffcmple, TR::iffcmpleu, TR::ifdcmpleu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpleEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeLS is for LE and ARMConditionCodeLE is for LEU bool isDouble = (node->getOpCodeValue() == TR::ifdcmple || node->getOpCodeValue() == TR::ifdcmpleu); bool unordered = (node->getOpCodeValue() == TR::iffcmpleu || node->getOpCodeValue() == TR::ifdcmpleu); ifFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeLE : ARMConditionCodeLS, cg, isDouble, false); return NULL; } // also handles TR::fcmpeq, TR::fcmpequ, TR::dcmpequ TR::Register *OMR::ARM::TreeEvaluator::dcmpeqEvaluator(TR::Node *node, TR::CodeGenerator *cg) { bool isDouble = (node->getOpCodeValue() == TR::dcmpeq || node->getOpCodeValue() == TR::dcmpequ); bool unordered = (node->getOpCodeValue() == TR::fcmpequ || node->getOpCodeValue() == TR::dcmpequ); return setboolFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, ARMConditionCodeEQ, cg, isDouble, unordered); } // also handles TR::fcmpne, TR::fcmpneu, TR::dcmpneu TR::Register *OMR::ARM::TreeEvaluator::dcmpneEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeNE may imply unordered, but looks like it is not used in common code bool isDouble = (node->getOpCodeValue() == TR::dcmpne || node->getOpCodeValue() == TR::dcmpneu); return setboolFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, ARMConditionCodeNE, cg, isDouble, false); } // also handles TR::fcmplt, TR::fcmpltu, TR::dcmpltu TR::Register *OMR::ARM::TreeEvaluator::dcmpltEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeCC is for LT and ARMConditionCodeLT is for LTU bool isDouble = (node->getOpCodeValue() == TR::dcmplt || node->getOpCodeValue() == TR::dcmpltu); bool unordered = (node->getOpCodeValue() == TR::fcmpltu || node->getOpCodeValue() == TR::dcmpltu); return setboolFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeLT : ARMConditionCodeCC, cg, isDouble, false); } // also handles TR::fcmpge TR::Register *OMR::ARM::TreeEvaluator::dcmpgeEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeGE is for GE and ARMConditionCodeCS is for GEU bool isDouble = (node->getOpCodeValue() == TR::dcmpge || node->getOpCodeValue() == TR::dcmpgeu); bool unordered = (node->getOpCodeValue() == TR::fcmpgeu || node->getOpCodeValue() == TR::dcmpgeu); return setboolFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeCS : ARMConditionCodeGE, cg, isDouble, false); } TR::Register *OMR::ARM::TreeEvaluator::dcmpgtEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeGT is for GT and ARMConditionCodeHI is for GTU bool isDouble = (node->getOpCodeValue() == TR::dcmpgt || node->getOpCodeValue() == TR::dcmpgtu); bool unordered = (node->getOpCodeValue() == TR::fcmpgtu || node->getOpCodeValue() == TR::dcmpgtu); return setboolFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeHI : ARMConditionCodeGT, cg, isDouble, false); } TR::Register *OMR::ARM::TreeEvaluator::dcmpleEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMConditionCodeLS is for LE and ARMConditionCodeLE is for LEU bool isDouble = (node->getOpCodeValue() == TR::dcmple || node->getOpCodeValue() == TR::dcmpleu); bool unordered = (node->getOpCodeValue() == TR::fcmpleu || node->getOpCodeValue() == TR::dcmpleu); return setboolFloatEvaluator(node, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, unordered ? ARMConditionCodeLE : ARMConditionCodeLS, cg, isDouble, false); } TR::Register *OMR::ARM::TreeEvaluator::dcmplEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Support TR::fcmpl, TR::dcmpg and TR::fcmpg as well // TR::dcmpl/TR::fcmpl (1 if c1 > c2, 0 if c1 == c2, -1 if c1 < c2 or unordered) // TR::dcmpg/TR::fcmpg (1 if c1 > c2 or unordered, 0 if c1 == c2, -1 if c1 < c2) TR::Node *firstChild = node->getFirstChild(); TR::Node *secondChild = node->getSecondChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Register *src2Reg = cg->evaluate(secondChild); TR::Register *trgReg = cg->allocateRegister(); bool isDouble = (node->getOpCodeValue() == TR::dcmpg || node->getOpCodeValue() == TR::dcmpl); bool isGType = (node->getOpCodeValue() == TR::dcmpg || node->getOpCodeValue() == TR::fcmpg); if (noFPRA) { if (isDouble) { generateSrc2Instruction(cg, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, node, moveToDoubleRegister(node, src1Reg, cg), moveToDoubleRegister(node, src2Reg, cg)); } else { generateSrc2Instruction(cg, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, node, moveToFloatRegister(node, src1Reg, cg), moveToFloatRegister(node, src2Reg, cg)); } } else { generateSrc2Instruction(cg, isDouble ? TR::InstOpCode::fcmpd : TR::InstOpCode::fcmps, node, src1Reg, src2Reg); } // Move the FPSCR flags back to the APSR generateInstruction(cg, TR::InstOpCode::fmstat, node); cg->decReferenceCount(firstChild); cg->decReferenceCount(secondChild); TR::Instruction *cursor = generateTrg1ImmInstruction(cg, TR::InstOpCode::mov, node, trgReg, 0, 0); cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::add, node, trgReg, trgReg, 1, 0, cursor); if (isGType) cursor->setConditionCode(ARMConditionCodeHI); // GT or unordered else cursor->setConditionCode(ARMConditionCodeGT); // GT cursor = generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::sub, node, trgReg, trgReg, 1, 0, cursor); if (isGType) cursor->setConditionCode(ARMConditionCodeCC); // LT else cursor->setConditionCode(ARMConditionCodeLT); // LT or unordered node->setRegister(trgReg); return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::fRegLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Support dRegLoad TR::Register *globalReg = node->getRegister(); if (globalReg == NULL) { globalReg = cg->allocateRegister(TR_FPR); if (node->getOpCodeValue() == TR::fRegLoad) globalReg->setIsSinglePrecision(); node->setRegister(globalReg); } return globalReg; } TR::Register *OMR::ARM::TreeEvaluator::fRegStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // Support dRegStore TR::Node *child = node->getFirstChild(); TR::Register *globalReg = cg->evaluate(child); cg->decReferenceCount(child); return globalReg; } static TR::Register *generateFloatMaxMin(TR::Node *node, TR::CodeGenerator *cg, bool max) { TR::Node *firstChild = node->getFirstChild(); TR::DataType data_type = firstChild->getDataType(); TR::DataType type = firstChild->getType(); TR::Instruction *cursor; TR::Register *trgReg, *trgFloatReg; if (data_type != TR::Float && data_type != TR::Double && node->getNumChildren() == 2) { TR_ASSERT(false, "assertion failure"); // We shouldn't get here at all } bool isFloat = (data_type == TR::Float); TR::Register *reg = cg->evaluate(firstChild); TR::LabelSymbol *doneLabel = TR::LabelSymbol::create(cg->trHeapMemory(),cg); if (noFPRA && reg->getKind() == TR_GPR) { trgFloatReg = isFloat ? moveToFloatRegister(node, reg, cg) : moveToDoubleRegister(node, reg, cg); trgReg = reg; } else { if (cg->canClobberNodesRegister(firstChild)) { trgFloatReg = reg; // use first child as a target } else { if (isFloat) { trgFloatReg = cg->allocateSinglePrecisionRegister(); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcpys, node, trgFloatReg, moveToFloatRegister(node, reg, cg)); } else { trgFloatReg = cg->allocateRegister(TR_FPR); generateTrg1Src1Instruction(cg, TR::InstOpCode::fcpyd, node, trgFloatReg, moveToDoubleRegister(node, reg, cg)); } } if (max) { trgReg = isFloat ? moveFromFloatRegister(node, reg, cg) : moveFromDoubleRegister(node, reg, cg); } } TR::Node *child = node->getChild(1); // Second child TR::Register *childReg = cg->evaluate(child); TR::Register *childFloatReg; if (noFPRA && childReg->getKind() == TR_GPR) { childFloatReg = (isFloat) ? moveToFloatRegister(node, childReg, cg) : moveToDoubleRegister(node, childReg, cg); } else { childFloatReg = childReg; if (!max) { childReg = (isFloat) ? moveFromFloatRegister(node, childFloatReg, cg) : moveFromDoubleRegister(node, childFloatReg, cg); } } TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 1, cg->trMemory()); deps->addPostCondition(trgFloatReg, TR::RealRegister::NoReg); // Check for NaN by comparing itself and leave generateSrc2Instruction(cg, (isFloat) ? TR::InstOpCode::fcmps : TR::InstOpCode::fcmpd, node, trgFloatReg, trgFloatReg); generateInstruction(cg, TR::InstOpCode::fmstat, node); generateConditionalBranchInstruction(cg, node, ARMConditionCodeVS, doneLabel, deps); // Check for NaN cursor = generateSrc2Instruction(cg, (isFloat) ? TR::InstOpCode::fcmps : TR::InstOpCode::fcmpd, node, childFloatReg, childFloatReg); cursor = generateInstruction(cg, TR::InstOpCode::fmstat, node, cursor); cursor = generateTrg1Src1Instruction(cg, (isFloat) ? TR::InstOpCode::fcpys : TR::InstOpCode::fcpyd, node, trgFloatReg, childFloatReg, cursor); cursor->setConditionCode(ARMConditionCodeVS); cursor = generateConditionalBranchInstruction(cg, node, ARMConditionCodeVS, doneLabel, deps, cursor); // TODO: Special case firstChild is -0.0, secondChild is 0.0, compare it in general register if (isFloat) { cursor = generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, max ? trgReg : childReg, 0x80, 24, cursor); // 0x80000000 } else { cursor = generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, max ? trgReg->getHighOrder() : childReg->getHighOrder(), 0x80, 24, cursor); // 0x80000000 cursor = generateSrc1ImmInstruction(cg, TR::InstOpCode::cmp, node, max ? trgReg->getLowOrder() : childReg->getLowOrder(), 0, 0, cursor); cursor->setConditionCode(ARMConditionCodeEQ); } /* * ;max: ;min: * ;compare child with zero if target is -0.0 ;compare target with zero if child is -0.0 * fcmpzdeq child fcmpzdeq target * fmstateq fmstateq * ;if child is zero, then return child (0.0). ;if target is zero, then return child (-0.0). * fcpydeq target child fcpydeq target child * ;if child is not zero, return greater one. ;if target is not zero, return lesser one. * fcmpdne child target fcmpdne child target * fmstatne fmstatne * fcpydhi target child fcpydlt target child * */ cursor = generateSrc1ImmInstruction(cg, (isFloat) ? TR::InstOpCode::fcmpzs : TR::InstOpCode::fcmpzd, node, max ? childFloatReg : trgFloatReg, 0, 0, cursor); // Dummy 0 cursor->setConditionCode(ARMConditionCodeEQ); cursor = generateInstruction(cg, TR::InstOpCode::fmstat, node, cursor); cursor->setConditionCode(ARMConditionCodeEQ); cursor = generateTrg1Src1Instruction(cg, (isFloat) ? TR::InstOpCode::fcpys : TR::InstOpCode::fcpyd, node, trgFloatReg, childFloatReg, cursor); cursor->setConditionCode(ARMConditionCodeEQ); cursor = generateSrc2Instruction(cg, (isFloat) ? TR::InstOpCode::fcmps : TR::InstOpCode::fcmpd, node, childFloatReg, trgFloatReg, cursor); cursor->setConditionCode(ARMConditionCodeNE); // Move the FPSCR flags back to the APSR cursor = generateInstruction(cg, TR::InstOpCode::fmstat, node, cursor); cursor->setConditionCode(ARMConditionCodeNE); cursor = generateTrg1Src1Instruction(cg, (isFloat) ? TR::InstOpCode::fcpys : TR::InstOpCode::fcpyd, node, trgFloatReg, childFloatReg, cursor); cursor->setConditionCode(max ? ARMConditionCodeHI: ARMConditionCodeLT); // doneLabel cursor = generateLabelInstruction(cg, TR::InstOpCode::label, node, doneLabel, deps, cursor); if (noFPRA && reg->getKind() == TR_GPR) { if (cg->canClobberNodesRegister(firstChild)) { if (isFloat) { cursor = generateTrg1Src1Instruction(cg, TR::InstOpCode::fmrs, node, reg, trgFloatReg, cursor); } else { cursor = generateTrg2Src1Instruction(cg, TR::InstOpCode::fmrrd, node, reg->getLowOrder(), reg->getHighOrder(), trgFloatReg, cursor); } trgReg = reg; } else { trgReg = (isFloat) ? moveFromFloatRegister(node, trgFloatReg, cg) : moveFromDoubleRegister(node, trgFloatReg, cg); cg->stopUsingRegister(trgFloatReg); } } else { trgReg = trgFloatReg; } node->setRegister(trgReg); for (int i = 0; i < 2; i++) // n = 2 { cg->decReferenceCount(node->getChild(i)); } return trgReg; } TR::Register *OMR::ARM::TreeEvaluator::fmaxEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return generateFloatMaxMin(node, cg, true); } TR::Register *OMR::ARM::TreeEvaluator::fminEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return generateFloatMaxMin(node, cg, false); } #else TR::Register *OMR::ARM::TreeEvaluator::ibits2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *target = cg->allocateRegister(); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, target, tempMR); tempMR->decNodeReferenceCounts(); } else { target = cg->evaluate(child); cg->decReferenceCount(child); } node->setRegister(target); return target; } TR::Register *OMR::ARM::TreeEvaluator::fbits2iEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::Register *target = cg->allocateRegister(); TR_ASSERT(!node->normalizeNanValues(), "Check NAN\n"); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, target, tempMR); tempMR->decNodeReferenceCounts(); } else { target = cg->evaluate(child); cg->decReferenceCount(child); } node->setRegister(target); return target; } TR::Register *OMR::ARM::TreeEvaluator::lbits2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::RegisterPair *pairTarget = NULL; TR::Register *target = NULL; TR::Register *lowReg = NULL; TR::Register *highReg = NULL; TR::Compilation *comp = cg->comp(); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *highMem, *lowMem; TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 8, cg); lowReg = cg->allocateRegister(); highReg = cg->allocateRegister(); highMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 0 : 4, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, highReg, highMem); lowMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 4 : 0, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, lowReg, lowMem); highMem->decNodeReferenceCounts(); lowMem->decNodeReferenceCounts(); pairTarget = cg->allocateRegisterPair(lowReg, highReg); node->setRegister(pairTarget); return pairTarget; } else { target = cg->evaluate(child); cg->decReferenceCount(child); node->setRegister(target); return target; } } TR::Register *OMR::ARM::TreeEvaluator::dbits2lEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::RegisterPair *pairTarget = NULL; TR::Register *target = NULL; TR::Register *lowReg = NULL; TR::Register *highReg = NULL; TR::Compilation *comp = cg->comp(); TR_ASSERT(!node->normalizeNanValues(), "Check NAN\n"); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { TR::MemoryReference *highMem, *lowMem; TR::MemoryReference *tempMR = new (cg->trHeapMemory()) TR::MemoryReference(child, 8, cg); lowReg = cg->allocateRegister(); highReg = cg->allocateRegister(); highMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 0 : 4, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, highReg, highMem); lowMem = new (cg->trHeapMemory()) TR::MemoryReference(*tempMR, (cg->comp()->target().cpu.isBigEndian()) ? 4 : 0, 4, cg); generateTrg1MemInstruction(cg, TR::InstOpCode::ldr, node, lowReg, lowMem); highMem->decNodeReferenceCounts(); lowMem->decNodeReferenceCounts(); pairTarget = cg->allocateRegisterPair(lowReg, highReg); node->setRegister(pairTarget); return pairTarget; } else { target = cg->evaluate(child); cg->decReferenceCount(child); node->setRegister(target); return target; } } TR::Register *OMR::ARM::TreeEvaluator::fconstEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dconstEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::floadi TR::Register *OMR::ARM::TreeEvaluator::floadEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::dloadi TR::Register *OMR::ARM::TreeEvaluator::dloadEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fstoreEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dstoreEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fstoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dstoreiEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::freturnEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dreturnEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::faddEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::daddEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dsubEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fsubEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fmulEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dmulEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fdivEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::ddivEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fremEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dremEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fabsEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dabsEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fnegEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dnegEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::i2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::i2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::l2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::l2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // f2i handled by d2iEvaluator // f2s handled by d2sEvaluator // f2c handled by d2cEvaluator // f2b handled by d2bEvaluator // f2l handled by d2lEvaluator TR::Register *OMR::ARM::TreeEvaluator::f2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::f2iEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::d2iEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles f2c TR::Register *OMR::ARM::TreeEvaluator::d2cEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles f2s TR::Register *OMR::ARM::TreeEvaluator::d2sEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles f2b TR::Register *OMR::ARM::TreeEvaluator::d2bEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::f2lEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::d2lEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::d2fEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::b2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles s2f TR::Register *OMR::ARM::TreeEvaluator::s2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles c2f TR::Register *OMR::ARM::TreeEvaluator::su2dEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpeq TR::Register *OMR::ARM::TreeEvaluator::ifdcmpeqEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpeq TR::Register *OMR::ARM::TreeEvaluator::ifdcmpneEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpeq TR::Register *OMR::ARM::TreeEvaluator::ifdcmpltEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpeq TR::Register *OMR::ARM::TreeEvaluator::ifdcmpgeEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpgt TR::Register *OMR::ARM::TreeEvaluator::ifdcmpgtEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmple TR::Register *OMR::ARM::TreeEvaluator::ifdcmpleEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpequ TR::Register *OMR::ARM::TreeEvaluator::ifdcmpequEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpltu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpltuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpgeu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpgeuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMOp_bge is really not less than which is equivalent to greater than equal to or unordered return NULL; } // also handles TR::iffcmpgtu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpgtuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::iffcmpleu TR::Register *OMR::ARM::TreeEvaluator::ifdcmpleuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { // ARMOp_ble is really not greater than which is equivalent to less than equal to or unordered return NULL; } // also handles TR::fcmpeq TR::Register *OMR::ARM::TreeEvaluator::dcmpeqEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::fcmpne TR::Register *OMR::ARM::TreeEvaluator::dcmpneEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::fcmplt TR::Register *OMR::ARM::TreeEvaluator::dcmpltEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } // also handles TR::fcmpge TR::Register *OMR::ARM::TreeEvaluator::dcmpgeEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpgtEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpleEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpequEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpltuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpgeuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpgtuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpleuEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmplEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::dcmpgEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fRegLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fRegStoreEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fmaxEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } TR::Register *OMR::ARM::TreeEvaluator::fminEvaluator(TR::Node *node, TR::CodeGenerator *cg) { return NULL; } #endif