Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(966)

Side by Side Diff: src/compiler/ia32/instruction-selector-ia32.cc

Issue 1259203002: [turbofan] Implement tail calls with differing stack parameter counts (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix bugs in frameless tail calls Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/base/adapters.h" 5 #include "src/base/adapters.h"
6 #include "src/compiler/instruction-selector-impl.h" 6 #include "src/compiler/instruction-selector-impl.h"
7 #include "src/compiler/node-matchers.h" 7 #include "src/compiler/node-matchers.h"
8 #include "src/compiler/node-properties.h" 8 #include "src/compiler/node-properties.h"
9 9
10 namespace v8 { 10 namespace v8 {
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 if (descriptor->NeedsFrameState()) { 827 if (descriptor->NeedsFrameState()) {
828 frame_state_descriptor = 828 frame_state_descriptor =
829 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount())); 829 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
830 } 830 }
831 831
832 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); 832 CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
833 833
834 // Compute InstructionOperands for inputs and outputs. 834 // Compute InstructionOperands for inputs and outputs.
835 InitializeCallBuffer(node, &buffer, true, true); 835 InitializeCallBuffer(node, &buffer, true, true);
836 836
837 InstructionBlock* current_block = sequence()->InstructionBlockAt(
838 RpoNumber::FromInt(current_block_->rpo_number()));
839 current_block->mark_needs_frame();
840 // TODO(danno): For now, any instruction block that needs a frame forces
841 // the entire function to have a frame.
842 sequence()->frame()->MarkNeedsFrame();
843
837 // Prepare for C function call. 844 // Prepare for C function call.
838 if (descriptor->IsCFunctionCall()) { 845 if (descriptor->IsCFunctionCall()) {
839 InstructionOperand temps[] = {g.TempRegister()}; 846 InstructionOperand temps[] = {g.TempRegister()};
840 size_t const temp_count = arraysize(temps); 847 size_t const temp_count = arraysize(temps);
841 Emit(kArchPrepareCallCFunction | 848 Emit(kArchPrepareCallCFunction |
842 MiscField::encode(static_cast<int>(descriptor->CParameterCount())), 849 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
843 0, nullptr, 0, nullptr, temp_count, temps); 850 0, nullptr, 0, nullptr, temp_count, temps);
844 851
845 // Poke any stack arguments. 852 // Poke any stack arguments.
846 for (size_t n = 0; n < buffer.pushed_nodes.size(); ++n) { 853 for (size_t n = 0; n < buffer.pushed_nodes.size(); ++n) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
895 } 902 }
896 903
897 // Emit the call instruction. 904 // Emit the call instruction.
898 size_t const output_count = buffer.outputs.size(); 905 size_t const output_count = buffer.outputs.size();
899 auto* outputs = output_count ? &buffer.outputs.front() : nullptr; 906 auto* outputs = output_count ? &buffer.outputs.front() : nullptr;
900 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), 907 Emit(opcode, output_count, outputs, buffer.instruction_args.size(),
901 &buffer.instruction_args.front())->MarkAsCall(); 908 &buffer.instruction_args.front())->MarkAsCall();
902 } 909 }
903 910
904 911
905 void InstructionSelector::VisitTailCall(Node* node) { 912 bool InstructionSelector::EmitTailCallSetup(Node* node, CallBuffer* buffer,
Benedikt Meurer 2015/07/30 06:47:24 See my comment in code-generator-ia32.cc. Can we s
913 InstructionCode* opcode) {
906 IA32OperandGenerator g(this); 914 IA32OperandGenerator g(this);
907 CallDescriptor const* descriptor = OpParameter<CallDescriptor const*>(node); 915 CallDescriptor const* descriptor = OpParameter<CallDescriptor const*>(node);
908 DCHECK_NE(0, descriptor->flags() & CallDescriptor::kSupportsTailCalls); 916 DCHECK_NE(0, descriptor->flags() & CallDescriptor::kSupportsTailCalls);
909 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kPatchableCallSite); 917 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kPatchableCallSite);
910 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kNeedsNopAfterCall); 918 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kNeedsNopAfterCall);
911 919
912 // TODO(turbofan): Relax restriction for stack parameters. 920 size_t stack_parameters_in = 0;
913 921 size_t preserved_stack_parameters_in = 0;
914 if (linkage()->GetIncomingDescriptor()->CanTailCall(node)) { 922 size_t stack_parameters_out = 0;
915 CallBuffer buffer(zone(), descriptor, nullptr); 923 size_t register_parameters_out = 0;
924 if (!linkage()->GetIncomingDescriptor()->CanTailCall(
925 node, &stack_parameters_in, &preserved_stack_parameters_in,
926 &stack_parameters_out, &register_parameters_out)) {
927 return false;
928 }
916 929
917 // Compute InstructionOperands for inputs and outputs. 930 // Compute InstructionOperands for inputs and outputs.
918 InitializeCallBuffer(node, &buffer, true, true); 931 InitializeCallBuffer(node, buffer, true, true);
919 932
920 // Select the appropriate opcode based on the call type. 933 // Select the appropriate opcode based on the call type.
921 InstructionCode opcode; 934 switch (descriptor->kind()) {
922 switch (descriptor->kind()) { 935 case CallDescriptor::kCallCodeObject:
923 case CallDescriptor::kCallCodeObject: 936 case CallDescriptor::kInterpreterDispatch:
924 case CallDescriptor::kInterpreterDispatch: 937 *opcode = kArchTailCallCodeObject;
925 opcode = kArchTailCallCodeObject; 938 break;
926 break; 939 case CallDescriptor::kCallJSFunction:
927 case CallDescriptor::kCallJSFunction: 940 *opcode = kArchTailCallJSFunction;
928 opcode = kArchTailCallJSFunction; 941 break;
929 break; 942 default:
930 default: 943 UNREACHABLE();
931 UNREACHABLE(); 944 return false;
932 return; 945 }
946 *opcode |= MiscField::encode(descriptor->flags());
947
948 DCHECK(Register::kMaxNumAllocatableRegisters > register_parameters_out);
949 int remaining_registers =
950 Register::kMaxNumAllocatableRegisters - register_parameters_out;
951 if (buffer->instruction_args[0].IsImmediate()) {
952 // If the destination of the call is immediate, then there is actually an
953 // additional register free.
954 remaining_registers++;
955 }
956 int pushed_parameters = 0;
957 size_t current = 0;
958
959 bool frame_has_been_deconstructed = false;
960
961 // If we need to overwrite the return address, reserve a register.
962 if (stack_parameters_out > stack_parameters_in) {
963 remaining_registers--;
964 }
965
966 buffer->instruction_args.push_back(
967 ImmediateOperand(ImmediateOperand::INLINE, kParametersReady));
968
969 for (Node* node : base::Reversed(buffer->pushed_nodes)) {
970 if (current == stack_parameters_in) {
971 DCHECK(remaining_registers > 0);
972 // Special case for the parameter which will replace the caller's
973 // return address: load into a register for swapping.
974 InstructionOperand value = g.UseRegister(node);
975 buffer->instruction_args.push_back(value);
976 buffer->instruction_args.push_back(
977 ImmediateOperand(ImmediateOperand::INLINE, kReplaceReturn));
978 } else if (current >= preserved_stack_parameters_in) {
979 int location = stack_parameters_in - current;
980 if (remaining_registers > 0) {
981 buffer->instruction_args.push_back(
982 ImmediateOperand(ImmediateOperand::INLINE, location));
983 InstructionOperand value =
984 g.CanBeImmediate(node) ? g.UseImmediate(node) : g.UseRegister(node);
985 buffer->instruction_args.push_back(value);
986 buffer->instruction_args.push_back(
987 ImmediateOperand(ImmediateOperand::INLINE, kStore));
988 if (!g.CanBeImmediate(node)) {
989 remaining_registers--;
990 }
991 } else {
992 if (!frame_has_been_deconstructed) {
993 buffer->instruction_args.push_back(
994 ImmediateOperand(ImmediateOperand::INLINE, kDeconstructFrame));
995 frame_has_been_deconstructed = true;
996 }
997 buffer->instruction_args.push_back(
998 ImmediateOperand(ImmediateOperand::INLINE, location));
999 InstructionOperand value =
1000 g.CanBeImmediate(node)
1001 ? g.UseImmediate(node)
1002 : IsSupported(ATOM) ? g.UseRegister(node) : g.Use(node);
1003 Emit(kIA32Push, g.NoOutput(), value);
1004 InstructionBlock* current_block = sequence()->InstructionBlockAt(
1005 RpoNumber::FromInt(current_block_->rpo_number()));
1006 current_block->mark_needs_frame();
1007 // TODO(danno): For now, any instruction block that needs a frame
1008 // forces the entire function to have a frame.
1009 sequence()->frame()->MarkNeedsFrame();
1010 ++pushed_parameters;
1011 buffer->instruction_args.push_back(
1012 ImmediateOperand(ImmediateOperand::INLINE, kPopAndStore));
1013 }
933 } 1014 }
934 opcode |= MiscField::encode(descriptor->flags()); 1015 current++;
1016 }
935 1017
1018 if (!frame_has_been_deconstructed) {
1019 buffer->instruction_args.push_back(
1020 ImmediateOperand(ImmediateOperand::INLINE, kDeconstructFrame));
1021 }
1022
1023 buffer->instruction_args.push_back(
1024 ImmediateOperand(ImmediateOperand::INLINE, pushed_parameters));
1025 int stack_delta =
1026 stack_parameters_out - static_cast<int>(stack_parameters_in);
1027 buffer->instruction_args.push_back(
1028 ImmediateOperand(ImmediateOperand::INLINE, stack_delta));
1029 sequence()->frame()->UpdateMaxTailCallStackDelta(stack_delta);
1030
1031 return true;
1032 }
1033
1034
1035 void InstructionSelector::VisitTailCall(Node* node) {
1036 CallDescriptor const* descriptor = OpParameter<CallDescriptor const*>(node);
1037 CallBuffer buffer(zone(), descriptor, nullptr);
1038 InstructionCode opcode;
1039 if (EmitTailCallSetup(node, &buffer, &opcode)) {
936 // Emit the tailcall instruction. 1040 // Emit the tailcall instruction.
937 Emit(opcode, 0, nullptr, buffer.instruction_args.size(), 1041 Emit(opcode, 0, nullptr, buffer.instruction_args.size(),
938 &buffer.instruction_args.front()); 1042 &buffer.instruction_args.front());
939 } else { 1043 } else {
1044 IA32OperandGenerator g(this);
940 FrameStateDescriptor* frame_state_descriptor = 1045 FrameStateDescriptor* frame_state_descriptor =
941 descriptor->NeedsFrameState() 1046 descriptor->NeedsFrameState()
942 ? GetFrameStateDescriptor( 1047 ? GetFrameStateDescriptor(
943 node->InputAt(static_cast<int>(descriptor->InputCount()))) 1048 node->InputAt(static_cast<int>(descriptor->InputCount())))
944 : nullptr; 1049 : nullptr;
945 1050
946 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); 1051 CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
947 1052
948 // Compute InstructionOperands for inputs and outputs. 1053 // Compute InstructionOperands for inputs and outputs.
949 InitializeCallBuffer(node, &buffer, true, true); 1054 InitializeCallBuffer(node, &buffer, true, true);
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
1343 if (CpuFeatures::IsSupported(SSE4_1)) { 1448 if (CpuFeatures::IsSupported(SSE4_1)) {
1344 flags |= MachineOperatorBuilder::kFloat64RoundDown | 1449 flags |= MachineOperatorBuilder::kFloat64RoundDown |
1345 MachineOperatorBuilder::kFloat64RoundTruncate; 1450 MachineOperatorBuilder::kFloat64RoundTruncate;
1346 } 1451 }
1347 return flags; 1452 return flags;
1348 } 1453 }
1349 1454
1350 } // namespace compiler 1455 } // namespace compiler
1351 } // namespace internal 1456 } // namespace internal
1352 } // namespace v8 1457 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698