[turbofan] Simplify handling of calls with saved registers.
This removes the explicit {kCallWithCallerSavedRegisters} opcode which is just a regular call node with special handling for saving/restoring caller saved registers before/after the call. This is now handled via the {CallDescriptor::kCallerSavedRegisters} flag. R=neis@chromium.org BUG=v8:9396 Change-Id: Ie6421085eb2be8a067040222cd5215a9b1013048 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1728611 Reviewed-by: Georg Neis <neis@chromium.org> Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#63021}
This commit is contained in:
parent
159df2488c
commit
51d1573b2a
@ -1056,7 +1056,6 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
|
||||
bool InstructionSelector::IsSourcePositionUsed(Node* node) {
|
||||
return (source_position_mode_ == kAllSourcePositions ||
|
||||
node->opcode() == IrOpcode::kCall ||
|
||||
node->opcode() == IrOpcode::kCallWithCallerSavedRegisters ||
|
||||
node->opcode() == IrOpcode::kTrapIf ||
|
||||
node->opcode() == IrOpcode::kTrapUnless ||
|
||||
node->opcode() == IrOpcode::kProtectedLoad ||
|
||||
@ -1078,7 +1077,6 @@ void InstructionSelector::VisitBlock(BasicBlock* block) {
|
||||
if (node->opcode() == IrOpcode::kStore ||
|
||||
node->opcode() == IrOpcode::kUnalignedStore ||
|
||||
node->opcode() == IrOpcode::kCall ||
|
||||
node->opcode() == IrOpcode::kCallWithCallerSavedRegisters ||
|
||||
node->opcode() == IrOpcode::kProtectedLoad ||
|
||||
node->opcode() == IrOpcode::kProtectedStore ||
|
||||
#define ADD_EFFECT_FOR_ATOMIC_OP(Opcode) \
|
||||
@ -1320,8 +1318,6 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
return MarkAsReference(node), VisitConstant(node);
|
||||
case IrOpcode::kCall:
|
||||
return VisitCall(node);
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
return VisitCallWithCallerSavedRegisters(node);
|
||||
case IrOpcode::kDeoptimizeIf:
|
||||
return VisitDeoptimizeIf(node);
|
||||
case IrOpcode::kDeoptimizeUnless:
|
||||
@ -2704,6 +2700,12 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
OperandGenerator g(this);
|
||||
auto call_descriptor = CallDescriptorOf(node->op());
|
||||
|
||||
if (call_descriptor->NeedsCallerSavedRegisters()) {
|
||||
Emit(kArchSaveCallerRegisters | MiscField::encode(static_cast<int>(
|
||||
call_descriptor->get_save_fp_mode())),
|
||||
g.NoOutput());
|
||||
}
|
||||
|
||||
FrameStateDescriptor* frame_state_descriptor = nullptr;
|
||||
if (call_descriptor->NeedsFrameState()) {
|
||||
frame_state_descriptor = GetFrameStateDescriptor(
|
||||
@ -2772,18 +2774,13 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
call_instr->MarkAsCall();
|
||||
|
||||
EmitPrepareResults(&(buffer.output_nodes), call_descriptor, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitCallWithCallerSavedRegisters(
|
||||
Node* node, BasicBlock* handler) {
|
||||
OperandGenerator g(this);
|
||||
const auto fp_mode = CallDescriptorOf(node->op())->get_save_fp_mode();
|
||||
Emit(kArchSaveCallerRegisters | MiscField::encode(static_cast<int>(fp_mode)),
|
||||
g.NoOutput());
|
||||
VisitCall(node, handler);
|
||||
Emit(kArchRestoreCallerRegisters |
|
||||
MiscField::encode(static_cast<int>(fp_mode)),
|
||||
g.NoOutput());
|
||||
if (call_descriptor->NeedsCallerSavedRegisters()) {
|
||||
Emit(kArchRestoreCallerRegisters |
|
||||
MiscField::encode(
|
||||
static_cast<int>(call_descriptor->get_save_fp_mode())),
|
||||
g.NoOutput());
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitTailCall(Node* node) {
|
||||
|
@ -621,8 +621,6 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
|
||||
void VisitProjection(Node* node);
|
||||
void VisitConstant(Node* node);
|
||||
void VisitCall(Node* call, BasicBlock* handler = nullptr);
|
||||
void VisitCallWithCallerSavedRegisters(Node* call,
|
||||
BasicBlock* handler = nullptr);
|
||||
void VisitDeoptimizeIf(Node* node);
|
||||
void VisitDeoptimizeUnless(Node* node);
|
||||
void VisitTrapIf(Node* node, TrapId trap_id);
|
||||
|
@ -140,8 +140,9 @@ namespace {
|
||||
|
||||
|
||||
// General code uses the above configuration data.
|
||||
CallDescriptor* Linkage::GetSimplifiedCDescriptor(
|
||||
Zone* zone, const MachineSignature* msig, bool set_initialize_root_flag) {
|
||||
CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
|
||||
const MachineSignature* msig,
|
||||
CallDescriptor::Flags flags) {
|
||||
DCHECK_LE(msig->parameter_count(), static_cast<size_t>(kMaxCParameters));
|
||||
|
||||
LocationSignature::Builder locations(zone, msig->return_count(),
|
||||
@ -220,10 +221,7 @@ CallDescriptor* Linkage::GetSimplifiedCDescriptor(
|
||||
// The target for C calls is always an address (i.e. machine pointer).
|
||||
MachineType target_type = MachineType::Pointer();
|
||||
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNoAllocate;
|
||||
if (set_initialize_root_flag) {
|
||||
flags |= CallDescriptor::kInitializeRootRegister;
|
||||
}
|
||||
flags |= CallDescriptor::kNoAllocate;
|
||||
|
||||
return new (zone) CallDescriptor( // --
|
||||
CallDescriptor::kCallAddress, // kind
|
||||
|
@ -179,7 +179,6 @@ SelectParameters const& SelectParametersOf(const Operator* const op) {
|
||||
|
||||
CallDescriptor const* CallDescriptorOf(const Operator* const op) {
|
||||
DCHECK(op->opcode() == IrOpcode::kCall ||
|
||||
op->opcode() == IrOpcode::kCallWithCallerSavedRegisters ||
|
||||
op->opcode() == IrOpcode::kTailCall);
|
||||
return OpParameter<CallDescriptor const*>(op);
|
||||
}
|
||||
@ -1481,31 +1480,6 @@ const Operator* CommonOperatorBuilder::Call(
|
||||
return new (zone()) CallOperator(call_descriptor);
|
||||
}
|
||||
|
||||
const Operator* CommonOperatorBuilder::CallWithCallerSavedRegisters(
|
||||
const CallDescriptor* call_descriptor) {
|
||||
class CallOperator final : public Operator1<const CallDescriptor*> {
|
||||
public:
|
||||
explicit CallOperator(const CallDescriptor* call_descriptor)
|
||||
: Operator1<const CallDescriptor*>(
|
||||
IrOpcode::kCallWithCallerSavedRegisters,
|
||||
call_descriptor->properties(), "CallWithCallerSavedRegisters",
|
||||
call_descriptor->InputCount() +
|
||||
call_descriptor->FrameStateCount(),
|
||||
Operator::ZeroIfPure(call_descriptor->properties()),
|
||||
Operator::ZeroIfEliminatable(call_descriptor->properties()),
|
||||
call_descriptor->ReturnCount(),
|
||||
Operator::ZeroIfPure(call_descriptor->properties()),
|
||||
Operator::ZeroIfNoThrow(call_descriptor->properties()),
|
||||
call_descriptor) {}
|
||||
|
||||
void PrintParameter(std::ostream& os,
|
||||
PrintVerbosity verbose) const override {
|
||||
os << "[" << *parameter() << "]";
|
||||
}
|
||||
};
|
||||
return new (zone()) CallOperator(call_descriptor);
|
||||
}
|
||||
|
||||
const Operator* CommonOperatorBuilder::TailCall(
|
||||
const CallDescriptor* call_descriptor) {
|
||||
class TailCallOperator final : public Operator1<const CallDescriptor*> {
|
||||
|
@ -530,8 +530,6 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
|
||||
OutputFrameStateCombine state_combine,
|
||||
const FrameStateFunctionInfo* function_info);
|
||||
const Operator* Call(const CallDescriptor* call_descriptor);
|
||||
const Operator* CallWithCallerSavedRegisters(
|
||||
const CallDescriptor* call_descriptor);
|
||||
const Operator* TailCall(const CallDescriptor* call_descriptor);
|
||||
const Operator* Projection(size_t index);
|
||||
const Operator* Retain();
|
||||
|
@ -197,7 +197,8 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
// Use the kJavaScriptCallCodeStartRegister (fixed) register for the
|
||||
// indirect target address when calling.
|
||||
kFixedTargetRegister = 1u << 7,
|
||||
kAllowCallThroughSlot = 1u << 8
|
||||
kAllowCallThroughSlot = 1u << 8,
|
||||
kCallerSavedRegisters = 1u << 9
|
||||
};
|
||||
using Flags = base::Flags<Flag>;
|
||||
|
||||
@ -276,6 +277,9 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
bool InitializeRootRegister() const {
|
||||
return flags() & kInitializeRootRegister;
|
||||
}
|
||||
bool NeedsCallerSavedRegisters() const {
|
||||
return flags() & kCallerSavedRegisters;
|
||||
}
|
||||
|
||||
LinkageLocation GetReturnLocation(size_t index) const {
|
||||
return location_sig_->GetReturn(index);
|
||||
@ -418,7 +422,7 @@ class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
// structs, pointers to members, etc.
|
||||
static CallDescriptor* GetSimplifiedCDescriptor(
|
||||
Zone* zone, const MachineSignature* sig,
|
||||
bool set_initialize_root_flag = false);
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
|
||||
|
||||
// Get the location of an (incoming) parameter to this function.
|
||||
LinkageLocation GetParameterLocation(int index) const {
|
||||
|
@ -60,8 +60,7 @@ class MachineRepresentationInferrer {
|
||||
CHECK_LE(index, static_cast<size_t>(1));
|
||||
return index == 0 ? MachineRepresentation::kWord64
|
||||
: MachineRepresentation::kBit;
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters: {
|
||||
case IrOpcode::kCall: {
|
||||
auto call_descriptor = CallDescriptorOf(input->op());
|
||||
return call_descriptor->GetReturnType(index).representation();
|
||||
}
|
||||
@ -142,8 +141,7 @@ class MachineRepresentationInferrer {
|
||||
representation_vector_[node->id()] =
|
||||
PhiRepresentationOf(node->op());
|
||||
break;
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters: {
|
||||
case IrOpcode::kCall: {
|
||||
auto call_descriptor = CallDescriptorOf(node->op());
|
||||
if (call_descriptor->ReturnCount() > 0) {
|
||||
representation_vector_[node->id()] =
|
||||
@ -373,7 +371,6 @@ class MachineRepresentationChecker {
|
||||
}
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
case IrOpcode::kTailCall:
|
||||
CheckCallInputs(node);
|
||||
break;
|
||||
|
@ -167,7 +167,6 @@ bool CanAllocate(const Node* node) {
|
||||
return false;
|
||||
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
return !(CallDescriptorOf(node->op())->flags() &
|
||||
CallDescriptor::kNoAllocate);
|
||||
default:
|
||||
@ -237,8 +236,6 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) {
|
||||
return VisitAllocateRaw(node, state);
|
||||
case IrOpcode::kCall:
|
||||
return VisitCall(node, state);
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
return VisitCallWithCallerSavedRegisters(node, state);
|
||||
case IrOpcode::kLoadFromObject:
|
||||
return VisitLoadFromObject(node, state);
|
||||
case IrOpcode::kLoadElement:
|
||||
@ -563,16 +560,6 @@ void MemoryOptimizer::VisitCall(Node* node, AllocationState const* state) {
|
||||
EnqueueUses(node, state);
|
||||
}
|
||||
|
||||
void MemoryOptimizer::VisitCallWithCallerSavedRegisters(
|
||||
Node* node, AllocationState const* state) {
|
||||
DCHECK_EQ(IrOpcode::kCallWithCallerSavedRegisters, node->opcode());
|
||||
// If the call can allocate, we start with a fresh state.
|
||||
if (!(CallDescriptorOf(node->op())->flags() & CallDescriptor::kNoAllocate)) {
|
||||
state = empty_state();
|
||||
}
|
||||
EnqueueUses(node, state);
|
||||
}
|
||||
|
||||
void MemoryOptimizer::VisitLoadElement(Node* node,
|
||||
AllocationState const* state) {
|
||||
DCHECK_EQ(IrOpcode::kLoadElement, node->opcode());
|
||||
|
@ -118,7 +118,6 @@ class MemoryOptimizer final {
|
||||
void VisitNode(Node*, AllocationState const*);
|
||||
void VisitAllocateRaw(Node*, AllocationState const*);
|
||||
void VisitCall(Node*, AllocationState const*);
|
||||
void VisitCallWithCallerSavedRegisters(Node*, AllocationState const*);
|
||||
void VisitLoadFromObject(Node*, AllocationState const*);
|
||||
void VisitLoadElement(Node*, AllocationState const*);
|
||||
void VisitLoadField(Node*, AllocationState const*);
|
||||
|
@ -66,7 +66,6 @@
|
||||
V(ObjectId) \
|
||||
V(TypedObjectState) \
|
||||
V(Call) \
|
||||
V(CallWithCallerSavedRegisters) \
|
||||
V(Parameter) \
|
||||
V(OsrValue) \
|
||||
V(LoopExit) \
|
||||
|
@ -713,8 +713,10 @@ Node* CallCFunctionImpl(
|
||||
builder.AddReturn(return_type);
|
||||
for (const auto& arg : args) builder.AddParam(arg.first);
|
||||
|
||||
auto call_descriptor =
|
||||
Linkage::GetSimplifiedCDescriptor(rasm->zone(), builder.Build());
|
||||
auto call_descriptor = Linkage::GetSimplifiedCDescriptor(
|
||||
rasm->zone(), builder.Build(),
|
||||
caller_saved_regs ? CallDescriptor::kCallerSavedRegisters
|
||||
: CallDescriptor::kNoFlags);
|
||||
|
||||
if (caller_saved_regs) call_descriptor->set_save_fp_mode(mode);
|
||||
|
||||
@ -725,10 +727,8 @@ Node* CallCFunctionImpl(
|
||||
[](const RawMachineAssembler::CFunctionArg& arg) { return arg.second; });
|
||||
|
||||
auto common = rasm->common();
|
||||
return rasm->AddNode(
|
||||
caller_saved_regs ? common->CallWithCallerSavedRegisters(call_descriptor)
|
||||
: common->Call(call_descriptor),
|
||||
static_cast<int>(nodes.size()), nodes.begin());
|
||||
return rasm->AddNode(common->Call(call_descriptor),
|
||||
static_cast<int>(nodes.size()), nodes.begin());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -215,7 +215,6 @@ bool IsPotentiallyThrowingCall(IrOpcode::Value opcode) {
|
||||
JS_OP_LIST(BUILD_BLOCK_JS_CASE)
|
||||
#undef BUILD_BLOCK_JS_CASE
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -359,7 +359,6 @@ class CFGBuilder : public ZoneObject {
|
||||
// JS opcodes are just like calls => fall through.
|
||||
#undef BUILD_BLOCK_JS_CASE
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
if (NodeProperties::IsExceptionalCall(node)) {
|
||||
BuildBlocksForSuccessors(node);
|
||||
}
|
||||
@ -404,7 +403,6 @@ class CFGBuilder : public ZoneObject {
|
||||
// JS opcodes are just like calls => fall through.
|
||||
#undef CONNECT_BLOCK_JS_CASE
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
if (NodeProperties::IsExceptionalCall(node)) {
|
||||
scheduler_->UpdatePlacement(node, Scheduler::kFixed);
|
||||
ConnectCall(node);
|
||||
|
@ -999,10 +999,6 @@ Type Typer::Visitor::TypeTypedObjectState(Node* node) {
|
||||
|
||||
Type Typer::Visitor::TypeCall(Node* node) { return Type::Any(); }
|
||||
|
||||
Type Typer::Visitor::TypeCallWithCallerSavedRegisters(Node* node) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Type Typer::Visitor::TypeProjection(Node* node) {
|
||||
Type const type = Operand(node, 0);
|
||||
if (type.Is(Type::None())) return Type::None();
|
||||
|
@ -580,7 +580,6 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
||||
// TODO(jarin): what are the constraints on these?
|
||||
break;
|
||||
case IrOpcode::kCall:
|
||||
case IrOpcode::kCallWithCallerSavedRegisters:
|
||||
// TODO(rossberg): what are the constraints on these?
|
||||
break;
|
||||
case IrOpcode::kTailCall:
|
||||
|
@ -6662,9 +6662,9 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
|
||||
MachineSignature incoming_sig(1, 4, sig_types);
|
||||
// Traps need the root register, for TailCallRuntimeWithCEntry to call
|
||||
// Runtime::kThrowWasmError.
|
||||
bool initialize_root_flag = true;
|
||||
CallDescriptor* incoming = Linkage::GetSimplifiedCDescriptor(
|
||||
zone.get(), &incoming_sig, initialize_root_flag);
|
||||
CallDescriptor::Flags flags = CallDescriptor::kInitializeRootRegister;
|
||||
CallDescriptor* incoming =
|
||||
Linkage::GetSimplifiedCDescriptor(zone.get(), &incoming_sig, flags);
|
||||
|
||||
// Build a name in the form "c-wasm-entry:<params>:<returns>".
|
||||
static constexpr size_t kMaxNameLen = 128;
|
||||
|
@ -34,7 +34,7 @@ class RawMachineAssemblerTester : public HandleAndZoneScope,
|
||||
main_zone(),
|
||||
CSignature::New(main_zone(), MachineTypeForC<ReturnType>(),
|
||||
p...),
|
||||
true),
|
||||
CallDescriptor::kInitializeRootRegister),
|
||||
MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags(),
|
||||
InstructionSelector::AlignmentRequirements()) {}
|
||||
@ -51,7 +51,7 @@ class RawMachineAssemblerTester : public HandleAndZoneScope,
|
||||
main_zone(),
|
||||
CSignature::New(main_zone(), MachineTypeForC<ReturnType>(),
|
||||
p...),
|
||||
true),
|
||||
CallDescriptor::kInitializeRootRegister),
|
||||
MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags(),
|
||||
InstructionSelector::AlignmentRequirements()),
|
||||
|
@ -458,8 +458,8 @@ Handle<Code> WasmFunctionWrapper::GetWrapperCode() {
|
||||
if (!code_.ToHandle(&code)) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
|
||||
auto call_descriptor =
|
||||
compiler::Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
|
||||
auto call_descriptor = compiler::Linkage::GetSimplifiedCDescriptor(
|
||||
zone(), signature_, CallDescriptor::kInitializeRootRegister);
|
||||
|
||||
if (kSystemPointerSize == 4) {
|
||||
size_t num_params = signature_->parameter_count();
|
||||
|
Loading…
Reference in New Issue
Block a user