void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, const RewriterVar::SmallVector& args, int num_slots, int slot_size) { assembler::Register r = allocReg(assembler::R11); if (args.size() > 6) { // only 6 args can get passed in registers. assert(args.size() <= 6 + JitCodeBlock::num_stack_args); for (int i = 6; i < args.size(); ++i) { assembler::Register reg = args[i]->getInReg(Location::any(), true); assembler->mov(reg, assembler::Indirect(assembler::RSP, sizeof(void*) * (i - 6))); } RewriterVar::SmallVector reg_args(args.begin(), args.begin() + 6); assert(reg_args.size() == 6); _setupCall(false, reg_args, RewriterVar::SmallVector()); } else _setupCall(false, args, RewriterVar::SmallVector()); if (failed) return; // make sure setupCall doesn't use R11 assert(vars_by_location.count(assembler::R11) == 0); int pp_size = slot_size * num_slots; // make space for patchpoint uint8_t* pp_start = rewrite->getSlotStart() + assembler->bytesWritten(); constexpr int call_size = 16; assembler->skipBytes(pp_size + call_size); uint8_t* pp_end = rewrite->getSlotStart() + assembler->bytesWritten(); assert(assembler->hasFailed() || (pp_start + pp_size + call_size == pp_end)); std::unique_ptr<ICSetupInfo> setup_info( ICSetupInfo::initialize(true, num_slots, slot_size, ICSetupInfo::Generic, NULL)); // calculate available scratch space int pp_scratch_size = 0; int pp_scratch_location = rewrite->getScratchRspOffset() + rewrite->getScratchSize(); for (int i = rewrite->getScratchSize() - 8; i >= 0; i -= 8) { Location l(Location::Scratch, i); if (vars_by_location.count(l)) break; pp_scratch_size += 8; pp_scratch_location -= 8; } for (RewriterVar* arg : args) { arg->bumpUse(); } assertConsistent(); StackInfo stack_info(pp_scratch_size, pp_scratch_location); pp_infos.emplace_back(PPInfo{ func_addr, pp_start, pp_end, std::move(setup_info), stack_info }); assert(vars_by_location.count(assembler::RAX) == 0); result->initializeInReg(assembler::RAX); assertConsistent(); result->releaseIfNoUses(); }
int Tile::eval(int want) { //save any hit registers int spill = hits; if (want_l) spill |= 1 << want_l; if (want_r) spill |= 1 << want_r; if (spill) { for (int n = 1; n <= NUM_REGS; ++n) { if (spill & (1 << n)) { if (regUsed[n]) pushReg(n); else spill &= ~(1 << n); } } } //if tile needs an argFrame... if (argFrame) { codeFrags.push_back("-" + itoa(argFrame)); } int got_l = 0, got_r = 0; if (want_l) want = want_l; std::string* as = &assem; if (!l) { got_l = allocReg(want); } else if (!r) { got_l = l->eval(want); } else { if (l->need >= NUM_REGS && r->need >= NUM_REGS) { got_r = r->eval(0); pushReg(got_r); freeReg(got_r); got_l = l->eval(want); got_r = allocReg(want_r); popReg(got_r); } else if (r->need > l->need) { got_r = r->eval(want_r); got_l = l->eval(want); } else { got_l = l->eval(want); got_r = r->eval(want_r); if (assem2.size()) as = &assem2; } if (want_l == got_r || want_r == got_l) { swapRegs(got_l, got_r); int t = got_l; got_l = got_r; got_r = t; } } if (!want_l) want_l = got_l; else if (want_l != got_l) moveReg(want_l, got_l); if (!want_r) want_r = got_r; else if (want_r != got_r) moveReg(want_r, got_r); int i; while ((i = as->find("%l")) != std::string::npos) as->replace(i, 2, regs[want_l]); while ((i = as->find("%r")) != std::string::npos) as->replace(i, 2, regs[want_r]); codeFrags.push_back(*as); freeReg(got_r); if (want_l != got_l) moveReg(got_l, want_l); //cleanup argFrame if (argFrame) { //***** Not needed for STDCALL ***** // codeFrags.push_back( "+"+itoa(argFrame) ); } //restore spilled regs if (spill) { for (int n = NUM_REGS; n >= 1; --n) { if (spill & (1 << n)) popReg(n); } } return got_l; }