const RegisterSet& StackmapSpecial::extraEarlyClobberedRegs(Inst& inst) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); return value->earlyClobbered(); }
RegisterSet StackmapSpecial::extraClobberedRegs(Inst& inst) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); return value->lateClobbered(); }
bool StackmapSpecial::admitsStackImpl( unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst, unsigned argIndex) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); unsigned stackmapArgIndex = argIndex - numIgnoredAirArgs + numIgnoredB3Args; if (stackmapArgIndex >= value->numChildren()) { // It's not a stackmap argument, so as far as we are concerned, it doesn't admit stack. return false; } if (stackmapArgIndex >= value->m_reps.size()) { // This means that there was no constraint. return true; } // We only admit stack for Any's, since Stack is not a valid input constraint, and StackArgument // translates to a CallArg in Air. if (value->m_reps[stackmapArgIndex].isAny()) return true; return false; }
void StackmapSpecial::forEachArgImpl( unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst, Arg::Role role, const ScopedLambda<Inst::EachArgCallback>& callback) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); // Check that insane things have not happened. ASSERT(inst.args.size() >= numIgnoredAirArgs); ASSERT(value->children().size() >= numIgnoredB3Args); ASSERT(inst.args.size() - numIgnoredAirArgs == value->children().size() - numIgnoredB3Args); for (unsigned i = 0; i < inst.args.size() - numIgnoredAirArgs; ++i) { Arg& arg = inst.args[i + numIgnoredAirArgs]; ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args); Arg::Role thisRole = role; // Cool down the role if the use is cold. if (child.rep().kind() == ValueRep::Any && thisRole == Arg::Use) thisRole = Arg::ColdUse; callback(arg, role, Arg::typeForB3Type(child.value()->type())); } }
void StackmapSpecial::forEachArgImpl( unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst, RoleMode roleMode, Optional<unsigned> firstRecoverableIndex, const ScopedLambda<Inst::EachArgCallback>& callback) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); // Check that insane things have not happened. ASSERT(inst.args.size() >= numIgnoredAirArgs); ASSERT(value->children().size() >= numIgnoredB3Args); ASSERT(inst.args.size() - numIgnoredAirArgs >= value->children().size() - numIgnoredB3Args); for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) { Arg& arg = inst.args[i + numIgnoredAirArgs]; ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args); Arg::Role role; switch (roleMode) { case ForceLateUseUnlessRecoverable: ASSERT(firstRecoverableIndex); if (arg != inst.args[*firstRecoverableIndex] && arg != inst.args[*firstRecoverableIndex + 1]) { role = Arg::LateColdUse; break; } FALLTHROUGH; case SameAsRep: switch (child.rep().kind()) { case ValueRep::WarmAny: case ValueRep::SomeRegister: case ValueRep::Register: case ValueRep::Stack: case ValueRep::StackArgument: case ValueRep::Constant: role = Arg::Use; break; case ValueRep::LateRegister: role = Arg::LateUse; break; case ValueRep::ColdAny: role = Arg::ColdUse; break; case ValueRep::LateColdAny: role = Arg::LateColdUse; break; default: RELEASE_ASSERT_NOT_REACHED(); break; } break; case ForceLateUse: role = Arg::LateColdUse; break; } Type type = child.value()->type(); callback(arg, role, Arg::typeForB3Type(type), Arg::widthForB3Type(type)); } }
void StackmapSpecial::forEachArgImpl( unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst, RoleMode roleMode, const ScopedLambda<Inst::EachArgCallback>& callback) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); // Check that insane things have not happened. ASSERT(inst.args.size() >= numIgnoredAirArgs); ASSERT(value->children().size() >= numIgnoredB3Args); ASSERT(inst.args.size() - numIgnoredAirArgs == value->children().size() - numIgnoredB3Args); for (unsigned i = 0; i < inst.args.size() - numIgnoredAirArgs; ++i) { Arg& arg = inst.args[i + numIgnoredAirArgs]; ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args); Arg::Role role; switch (roleMode) { case SameAsRep: switch (child.rep().kind()) { case ValueRep::WarmAny: case ValueRep::SomeRegister: case ValueRep::Register: case ValueRep::Stack: case ValueRep::StackArgument: case ValueRep::Constant: role = Arg::Use; break; case ValueRep::ColdAny: role = Arg::ColdUse; break; case ValueRep::LateColdAny: role = Arg::LateUse; break; } break; case ForceLateUse: role = Arg::LateUse; break; } callback(arg, role, Arg::typeForB3Type(child.value()->type())); } }
bool StackmapSpecial::isValidImpl( unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); // Check that insane things have not happened. ASSERT(inst.args.size() >= numIgnoredAirArgs); ASSERT(value->children().size() >= numIgnoredB3Args); // For the Inst to be valid, it needs to have the right number of arguments. if (inst.args.size() - numIgnoredAirArgs != value->children().size() - numIgnoredB3Args) return false; // Regardless of constraints, stackmaps have some basic requirements for their arguments. For // example, you can't have a non-FP-offset address. This verifies those conditions as well as the // argument types. for (unsigned i = 0; i < inst.args.size() - numIgnoredAirArgs; ++i) { Value* child = value->child(i + numIgnoredB3Args); Arg& arg = inst.args[i + numIgnoredAirArgs]; if (!isArgValidForValue(arg, child)) return false; } // The number of constraints has to be no greater than the number of B3 children. ASSERT(value->m_reps.size() <= value->children().size()); // Verify any explicitly supplied constraints. for (unsigned i = numIgnoredB3Args; i < value->m_reps.size(); ++i) { ValueRep& rep = value->m_reps[i]; Arg& arg = inst.args[i - numIgnoredB3Args + numIgnoredAirArgs]; if (!isArgValidForRep(code(), arg, rep)) return false; } return true; }
bool StackmapSpecial::isValidImpl( unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst) { StackmapValue* value = inst.origin->as<StackmapValue>(); ASSERT(value); // Check that insane things have not happened. ASSERT(inst.args.size() >= numIgnoredAirArgs); ASSERT(value->children().size() >= numIgnoredB3Args); // For the Inst to be valid, it needs to have the right number of arguments. if (inst.args.size() - numIgnoredAirArgs != value->children().size() - numIgnoredB3Args) return false; // Regardless of constraints, stackmaps have some basic requirements for their arguments. For // example, you can't have a non-FP-offset address. This verifies those conditions as well as the // argument types. for (unsigned i = 0; i < inst.args.size() - numIgnoredAirArgs; ++i) { Value* child = value->child(i + numIgnoredB3Args); Arg& arg = inst.args[i + numIgnoredAirArgs]; switch (arg.kind()) { case Arg::Tmp: case Arg::Imm: case Arg::Imm64: case Arg::Stack: case Arg::CallArg: break; // OK case Arg::Addr: if (arg.base() != Tmp(GPRInfo::callFrameRegister) && arg.base() != Tmp(MacroAssembler::stackPointerRegister)) return false; break; default: return false; } Arg::Type type = Arg::typeForB3Type(child->type()); if (!arg.isType(type)) return false; } // The number of constraints has to be no greater than the number of B3 children. ASSERT(value->m_reps.size() <= value->children().size()); // Verify any explicitly supplied constraints. for (unsigned i = numIgnoredB3Args; i < value->m_reps.size(); ++i) { ValueRep& rep = value->m_reps[i]; Arg& arg = inst.args[i - numIgnoredB3Args + numIgnoredAirArgs]; switch (rep.kind()) { case ValueRep::Any: // We already verified this above. break; case ValueRep::SomeRegister: if (!arg.isTmp()) return false; break; case ValueRep::Register: if (arg != Tmp(rep.reg())) return false; break; case ValueRep::Stack: // This is not a valid input representation. ASSERT_NOT_REACHED(); break; case ValueRep::StackArgument: if (arg == Arg::callArg(rep.offsetFromSP())) break; if (arg.isAddr() && code().frameSize()) { if (arg.base() == Tmp(GPRInfo::callFrameRegister) && arg.offset() == rep.offsetFromSP() - code().frameSize()) break; if (arg.base() == Tmp(MacroAssembler::stackPointerRegister) && arg.offset() == rep.offsetFromSP()) break; } return false; case ValueRep::Constant: // This is not a valid input representation. ASSERT_NOT_REACHED(); break; } } return true; }