[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:
Michael Starzinger 2019-07-31 11:40:06 +02:00 committed by Commit Bot
parent 159df2488c
commit 51d1573b2a
18 changed files with 37 additions and 94 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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*> {

View File

@ -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();

View File

@ -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 {

View File

@ -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;

View File

@ -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());

View File

@ -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*);

View File

@ -66,7 +66,6 @@
V(ObjectId) \
V(TypedObjectState) \
V(Call) \
V(CallWithCallerSavedRegisters) \
V(Parameter) \
V(OsrValue) \
V(LoopExit) \

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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:

View File

@ -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;

View File

@ -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()),

View File

@ -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();