TR::Register *TR::IA32SystemLinkage::buildDirectDispatch(TR::Node *callNode, bool spillFPRegs) { TR::RealRegister *stackPointerReg = machine()->getX86RealRegister(TR::RealRegister::esp); TR::SymbolReference *methodSymRef = callNode->getSymbolReference(); TR::MethodSymbol *methodSymbol = callNode->getSymbol()->castToMethodSymbol(); TR::ILOpCodes callOpCodeValue = callNode->getOpCodeValue(); if (!methodSymbol->isHelper()) diagnostic("Building call site for %s\n", methodSymbol->getMethod()->signature(trMemory())); TR::RegisterDependencyConditions *deps; deps = generateRegisterDependencyConditions((uint8_t)0, (uint8_t)6, cg()); TR::Register *returnReg = buildVolatileAndReturnDependencies(callNode, deps); deps->stopAddingConditions(); TR::RegisterDependencyConditions *dummy = generateRegisterDependencyConditions((uint8_t)0, (uint8_t)0, cg()); uint32_t argSize = buildArgs(callNode, dummy); TR::Register* targetAddressReg = NULL; TR::MemoryReference* targetAddressMem = NULL; // Call-out int32_t stackAdjustment = cg()->getProperties().getCallerCleanup() ? 0 : -argSize; TR::X86ImmInstruction* instr = generateImmSymInstruction(CALLImm4, callNode, (uintptr_t)methodSymbol->getMethodAddress(), methodSymRef, cg()); instr->setAdjustsFramePointerBy(stackAdjustment); if (cg()->getProperties().getCallerCleanup() && argSize > 0) { // Clean up arguments // generateRegImmInstruction( (argSize <= 127) ? ADD4RegImms : ADD4RegImm4, callNode, stackPointerReg, argSize, cg() ); } // Label denoting end of dispatch code sequence; dependencies are on // this label rather than on the call // TR::LabelSymbol *endSystemCallSequence = generateLabelSymbol(cg()); generateLabelInstruction(LABEL, callNode, endSystemCallSequence, deps, cg()); // Stop using the killed registers that are not going to persist // if (deps) stopUsingKilledRegisters(deps, returnReg); // If the method returns a floating point value that is not used, insert a dummy store to // eventually pop the value from the floating point stack. // if ((callNode->getDataType() == TR::Float || callNode->getDataType() == TR::Double) && callNode->getReferenceCount() == 1) { generateFPSTiST0RegRegInstruction(FSTRegReg, callNode, returnReg, returnReg, cg()); } if (cg()->enableRegisterAssociations()) associatePreservedRegisters(deps, returnReg); return returnReg; }
TR::Register *TR::AMD64SystemLinkage::buildDirectDispatch( TR::Node *callNode, bool spillFPRegs) { TR::SymbolReference *methodSymRef = callNode->getSymbolReference(); TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol(); TR::Register *returnReg; // Allocate adequate register dependencies. // // pre = number of argument registers // post = number of volatile + return register // uint32_t pre = getProperties().getNumIntegerArgumentRegisters() + getProperties().getNumFloatArgumentRegisters(); uint32_t post = getProperties().getNumVolatileRegisters() + (callNode->getDataType() == TR::NoType ? 0 : 1); #if defined (PYTHON) && 0 // Treat all preserved GP regs as volatile until register map support available. // post += getProperties().getNumberOfPreservedGPRegisters(); #endif TR::RegisterDependencyConditions *preDeps = generateRegisterDependencyConditions(pre, 0, cg()); TR::RegisterDependencyConditions *postDeps = generateRegisterDependencyConditions(0, post, cg()); // Evaluate outgoing arguments on the system stack and build pre-conditions. // int32_t memoryArgSize = buildArgs(callNode, preDeps); // Build post-conditions. // returnReg = buildVolatileAndReturnDependencies(callNode, postDeps); postDeps->stopAddingPostConditions(); // Find the second scratch register in the post dependency list. // TR::Register *scratchReg = NULL; TR::RealRegister::RegNum scratchRegIndex = getProperties().getIntegerScratchRegister(1); for (int32_t i=0; i<post; i++) { if (postDeps->getPostConditions()->getRegisterDependency(i)->getRealRegister() == scratchRegIndex) { scratchReg = postDeps->getPostConditions()->getRegisterDependency(i)->getRegister(); break; } } #if defined(PYTHON) && 0 // For Python, store the instruction that contains the GC map at this site into // the frame object. // TR::SymbolReference *frameObjectSymRef = comp()->getSymRefTab()->findOrCreateAutoSymbol(comp()->getMethodSymbol(), 0, TR::Address, true, false, true); TR::Register *frameObjectRegister = cg()->allocateRegister(); generateRegMemInstruction( L8RegMem, callNode, frameObjectRegister, generateX86MemoryReference(frameObjectSymRef, cg()), cg()); TR::RealRegister *espReal = cg()->machine()->getX86RealRegister(TR::RealRegister::esp); TR::Register *gcMapPCRegister = cg()->allocateRegister(); generateRegMemInstruction( LEA8RegMem, callNode, gcMapPCRegister, generateX86MemoryReference(espReal, -8, cg()), cg()); // Use "volatile" registers across the call. Once proper register map support // is implemented, r14 and r15 will no longer be volatile and a different pair // should be chosen. // TR::RegisterDependencyConditions *gcMapDeps = generateRegisterDependencyConditions(0, 2, cg()); gcMapDeps->addPostCondition(frameObjectRegister, TR::RealRegister::r14, cg()); gcMapDeps->addPostCondition(gcMapPCRegister, TR::RealRegister::r15, cg()); gcMapDeps->stopAddingPostConditions(); generateMemRegInstruction( S8MemReg, callNode, generateX86MemoryReference(frameObjectRegister, fe()->getPythonGCMapPCOffsetInFrame(), cg()), gcMapPCRegister, gcMapDeps, cg()); cg()->stopUsingRegister(frameObjectRegister); cg()->stopUsingRegister(gcMapPCRegister); #endif TR::Instruction *instr; if (methodSymbol->getMethodAddress()) { TR_ASSERT(scratchReg, "could not find second scratch register"); auto LoadRegisterInstruction = generateRegImm64SymInstruction( MOV8RegImm64, callNode, scratchReg, (uintptr_t)methodSymbol->getMethodAddress(), methodSymRef, cg()); if (TR::Options::getCmdLineOptions()->getOption(TR_EmitRelocatableELFFile)) { LoadRegisterInstruction->setReloKind(TR_NativeMethodAbsolute); } instr = generateRegInstruction(CALLReg, callNode, scratchReg, preDeps, cg()); } else { instr = generateImmSymInstruction(CALLImm4, callNode, (uintptrj_t)methodSymbol->getMethodAddress(), methodSymRef, preDeps, cg()); } cg()->resetIsLeafMethod(); instr->setNeedsGCMap(getProperties().getPreservedRegisterMapForGC()); cg()->stopUsingRegister(scratchReg); TR::LabelSymbol *postDepLabel = generateLabelSymbol(cg()); generateLabelInstruction(LABEL, callNode, postDepLabel, postDeps, cg()); return returnReg; }
void TR_Debug::print(TR::FILE *pOutFile, TR::S390CallSnippet * snippet) { uint8_t * bufferPos = snippet->getSnippetLabel()->getCodeLocation(); TR::Node * callNode = snippet->getNode(); TR::SymbolReference * methodSymRef = snippet->getRealMethodSymbolReference(); if(!methodSymRef) methodSymRef = callNode->getSymbolReference(); TR::MethodSymbol * methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol(); TR::SymbolReference * glueRef; int8_t padbytes = snippet->getPadBytes(); printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, methodSymRef->isUnresolved() ? "Unresolved Call Snippet" : "Call Snippet"); bufferPos = printS390ArgumentsFlush(pOutFile, callNode, bufferPos, snippet->getSizeOfArguments()); if (methodSymRef->isUnresolved() || _comp->compileRelocatableCode()) { if (methodSymbol->isSpecial()) { glueRef = _cg->getSymRef(TR_S390interpreterUnresolvedSpecialGlue); } else if (methodSymbol->isStatic()) { glueRef = _cg->getSymRef(TR_S390interpreterUnresolvedStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterUnresolvedDirectVirtualGlue); } } else { bool synchronised = methodSymbol->isSynchronised(); if ((methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())) { glueRef = _cg->getSymRef(TR_S390nativeStaticHelper); } else { switch (callNode->getDataType()) { case TR::NoType: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncVoidStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterVoidStaticGlue); } break; case TR::Int8: case TR::Int16: case TR::Int32: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncIntStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterIntStaticGlue); } break; case TR::Address: if (TR::Compiler->target.is64Bit()) { if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncLongStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterLongStaticGlue); } } else { if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncIntStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterIntStaticGlue); } } break; case TR::Int64: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncLongStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterLongStaticGlue); } break; case TR::Float: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncFloatStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterFloatStaticGlue); } break; case TR::Double: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncDoubleStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterDoubleStaticGlue); } break; default: TR_ASSERT(0, "Bad return data type for a call node. DataType was %s\n", getName(callNode->getDataType())); } } } bufferPos = printRuntimeInstrumentationOnOffInstruction(pOutFile, bufferPos, false); // RIOFF if (snippet->getKind() == TR::Snippet::IsUnresolvedCall) { int lengthOfLoad = (TR::Compiler->target.is64Bit())?6:4; printPrefix(pOutFile, NULL, bufferPos, 6); trfprintf(pOutFile, "LARL \tGPR14, *+%d <%p>\t# Start of Data Const.", 8 + lengthOfLoad + padbytes, bufferPos + 8 + lengthOfLoad + padbytes); bufferPos += 6; if (TR::Compiler->target.is64Bit()) { printPrefix(pOutFile, NULL, bufferPos, 6); trfprintf(pOutFile, "LG \tGPR_EP, 0(,GPR14)"); bufferPos += 6; } else { printPrefix(pOutFile, NULL, bufferPos, 4); trfprintf(pOutFile, "L \tGPR_EP, 0(,GPR14)"); bufferPos += 4; } printPrefix(pOutFile, NULL, bufferPos, 2); trfprintf(pOutFile, "BCR \tGPR_EP"); bufferPos += 2; } else { printPrefix(pOutFile, NULL, bufferPos, 6); trfprintf(pOutFile, "BRASL \tGPR14, <%p>\t# Branch to Helper Method %s", snippet->getSnippetDestAddr(), snippet->usedTrampoline()?"- Trampoline Used.":""); bufferPos += 6; } if (padbytes == 2) { printPrefix(pOutFile, NULL, bufferPos, 2); trfprintf(pOutFile, "DC \t0x0000 \t\t\t# 2-bytes padding for alignment"); bufferPos += 2; } else if (padbytes == 4) { printPrefix(pOutFile, NULL, bufferPos, 4) ; trfprintf(pOutFile, "DC \t0x00000000 \t\t# 4-bytes padding for alignment"); bufferPos += 4; } else if (padbytes == 6) { printPrefix(pOutFile, NULL, bufferPos, 6) ; trfprintf(pOutFile, "DC \t0x000000000000 \t\t# 6-bytes padding for alignment"); bufferPos += 6; } printPrefix(pOutFile, NULL, bufferPos, sizeof(intptrj_t)); trfprintf(pOutFile, "DC \t%p \t\t# Method Address", glueRef->getMethodAddress()); bufferPos += sizeof(intptrj_t); printPrefix(pOutFile, NULL, bufferPos, sizeof(intptrj_t)); trfprintf(pOutFile, "DC \t%p \t\t# Call Site RA", snippet->getCallRA()); bufferPos += sizeof(intptrj_t); if (methodSymRef->isUnresolved()) { printPrefix(pOutFile, NULL, bufferPos, 0); } else { printPrefix(pOutFile, NULL, bufferPos, sizeof(intptrj_t)); } trfprintf(pOutFile, "DC \t%p \t\t# Method Pointer", methodSymRef->isUnresolved() ? 0 : methodSymbol->getMethodAddress()); }
TR::Register *TR::ARM64SystemLinkage::buildDirectDispatch(TR::Node *callNode) { TR::SymbolReference *callSymRef = callNode->getSymbolReference(); const TR::ARM64LinkageProperties &pp = getProperties(); TR::RealRegister *sp = cg()->machine()->getRealRegister(pp.getStackPointerRegister()); TR::RegisterDependencyConditions *dependencies = new (trHeapMemory()) TR::RegisterDependencyConditions( pp.getNumberOfDependencyGPRegisters(), pp.getNumberOfDependencyGPRegisters(), trMemory()); int32_t totalSize = buildArgs(callNode, dependencies); if (totalSize > 0) { if (constantIsUnsignedImm12(totalSize)) { generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::subimmx, callNode, sp, sp, totalSize); } else { TR_ASSERT_FATAL(false, "Too many arguments."); } } TR::MethodSymbol *callSymbol = callSymRef->getSymbol()->castToMethodSymbol(); generateImmSymInstruction(cg(), TR::InstOpCode::bl, callNode, (uintptr_t)callSymbol->getMethodAddress(), dependencies, callSymRef ? callSymRef : callNode->getSymbolReference(), NULL); cg()->machine()->setLinkRegisterKilled(true); if (totalSize > 0) { if (constantIsUnsignedImm12(totalSize)) { generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::addimmx, callNode, sp, sp, totalSize); } else { TR_ASSERT_FATAL(false, "Too many arguments."); } } TR::Register *retReg; switch(callNode->getOpCodeValue()) { case TR::icall: case TR::iucall: retReg = dependencies->searchPostConditionRegister( pp.getIntegerReturnRegister()); break; case TR::lcall: case TR::lucall: case TR::acall: retReg = dependencies->searchPostConditionRegister( pp.getLongReturnRegister()); break; case TR::fcall: case TR::dcall: retReg = dependencies->searchPostConditionRegister( pp.getFloatReturnRegister()); break; case TR::call: retReg = NULL; break; default: retReg = NULL; TR_ASSERT(false, "Unsupported direct call Opcode."); } callNode->setRegister(retReg); return retReg; }
TR::Register *TR::AMD64SystemLinkage::buildDirectDispatch( TR::Node *callNode, bool spillFPRegs) { TR::SymbolReference *methodSymRef = callNode->getSymbolReference(); TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol(); TR::Register *returnReg; // Allocate adequate register dependencies. // // pre = number of argument registers // post = number of volatile + return register // uint32_t pre = getProperties().getNumIntegerArgumentRegisters() + getProperties().getNumFloatArgumentRegisters(); uint32_t post = getProperties().getNumVolatileRegisters() + (callNode->getDataType() == TR::NoType ? 0 : 1); TR::RegisterDependencyConditions *preDeps = generateRegisterDependencyConditions(pre, 0, cg()); TR::RegisterDependencyConditions *postDeps = generateRegisterDependencyConditions(0, post, cg()); // Evaluate outgoing arguments on the system stack and build pre-conditions. // int32_t memoryArgSize = buildArgs(callNode, preDeps); // Build post-conditions. // returnReg = buildVolatileAndReturnDependencies(callNode, postDeps); postDeps->stopAddingPostConditions(); // Find the second scratch register in the post dependency list. // TR::Register *scratchReg = NULL; TR::RealRegister::RegNum scratchRegIndex = getProperties().getIntegerScratchRegister(1); for (int32_t i=0; i<post; i++) { if (postDeps->getPostConditions()->getRegisterDependency(i)->getRealRegister() == scratchRegIndex) { scratchReg = postDeps->getPostConditions()->getRegisterDependency(i)->getRegister(); break; } } TR::Instruction *instr; if (methodSymbol->getMethodAddress()) { TR_ASSERT(scratchReg, "could not find second scratch register"); auto LoadRegisterInstruction = generateRegImm64SymInstruction( MOV8RegImm64, callNode, scratchReg, (uintptr_t)methodSymbol->getMethodAddress(), methodSymRef, cg()); if (comp()->getOption(TR_EmitRelocatableELFFile)) { LoadRegisterInstruction->setReloKind(TR_NativeMethodAbsolute); } instr = generateRegInstruction(CALLReg, callNode, scratchReg, preDeps, cg()); } else { instr = generateImmSymInstruction(CALLImm4, callNode, (uintptrj_t)methodSymbol->getMethodAddress(), methodSymRef, preDeps, cg()); } cg()->resetIsLeafMethod(); instr->setNeedsGCMap(getProperties().getPreservedRegisterMapForGC()); cg()->stopUsingRegister(scratchReg); TR::LabelSymbol *postDepLabel = generateLabelSymbol(cg()); generateLabelInstruction(LABEL, callNode, postDepLabel, postDeps, cg()); return returnReg; }