Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/assembler-inl.h"
6 : #include "src/code-stub-assembler.h"
7 : #include "src/macro-assembler.h"
8 :
9 : #include "test/cctest/cctest.h"
10 : #include "test/cctest/compiler/code-assembler-tester.h"
11 : #include "test/cctest/compiler/function-tester.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 : namespace compiler {
16 : namespace test_run_retpoline {
17 :
18 : #define __ assembler.
19 :
20 : namespace {
21 :
22 : // Function that takes a number of pointer-sized integer arguments, calculates a
23 : // weighted sum of them and returns it.
24 128 : Handle<Code> BuildCallee(Isolate* isolate, CallDescriptor* call_descriptor) {
25 256 : CodeAssemblerTester tester(isolate, call_descriptor, "callee");
26 128 : CodeStubAssembler assembler(tester.state());
27 128 : int param_count = static_cast<int>(call_descriptor->StackParameterCount());
28 256 : Node* sum = __ IntPtrConstant(0);
29 576 : for (int i = 0; i < param_count; ++i) {
30 896 : Node* product = __ IntPtrMul(__ Parameter(i), __ IntPtrConstant(i + 1));
31 448 : sum = __ IntPtrAdd(sum, product);
32 : }
33 128 : __ Return(sum);
34 128 : return tester.GenerateCodeCloseAndEscape();
35 : }
36 :
37 : // Function that tail-calls another function with a number of pointer-sized
38 : // integer arguments.
39 128 : Handle<Code> BuildCaller(Isolate* isolate, CallDescriptor* call_descriptor,
40 : CallDescriptor* callee_descriptor, bool tail) {
41 256 : CodeAssemblerTester tester(isolate, call_descriptor, "caller");
42 128 : CodeStubAssembler assembler(tester.state());
43 : std::vector<Node*> params;
44 : // The first parameter is always the callee.
45 128 : Handle<Code> callee = BuildCallee(isolate, callee_descriptor);
46 : // defeat the instruction selector.
47 : CodeStubAssembler::Variable target_var(&assembler,
48 256 : MachineRepresentation::kTagged);
49 128 : CodeStubAssembler::Label t(&assembler), f(&assembler),
50 128 : end(&assembler, &target_var);
51 256 : __ Branch(__ Int32Constant(0), &t, &f);
52 128 : __ BIND(&t);
53 128 : target_var.Bind(__ HeapConstant(callee));
54 128 : __ Goto(&end);
55 128 : __ BIND(&f);
56 128 : target_var.Bind(__ HeapConstant(callee));
57 128 : __ Goto(&end);
58 128 : __ BIND(&end);
59 256 : params.push_back(target_var.value());
60 :
61 128 : int param_count = static_cast<int>(callee_descriptor->StackParameterCount());
62 576 : for (int i = 0; i < param_count; ++i) {
63 672 : params.push_back(__ IntPtrConstant(i));
64 : }
65 : DCHECK_EQ(param_count + 1, params.size());
66 128 : if (tail) {
67 64 : tester.raw_assembler_for_testing()->TailCallN(
68 64 : callee_descriptor, param_count + 1, params.data());
69 : } else {
70 64 : Node* result = tester.raw_assembler_for_testing()->CallN(
71 64 : callee_descriptor, param_count + 1, params.data());
72 64 : __ Return(result);
73 : }
74 128 : return tester.GenerateCodeCloseAndEscape();
75 : }
76 :
77 : // Setup function, which calls "caller".
78 128 : Handle<Code> BuildSetupFunction(Isolate* isolate,
79 : CallDescriptor* caller_descriptor,
80 : CallDescriptor* callee_descriptor, bool tail) {
81 256 : CodeAssemblerTester tester(isolate, 0);
82 128 : CodeStubAssembler assembler(tester.state());
83 : std::vector<Node*> params;
84 : // The first parameter is always the callee.
85 256 : params.push_back(__ HeapConstant(
86 128 : BuildCaller(isolate, caller_descriptor, callee_descriptor, tail)));
87 : // Set up arguments for "Caller".
88 128 : int param_count = static_cast<int>(caller_descriptor->StackParameterCount());
89 512 : for (int i = 0; i < param_count; ++i) {
90 : // Use values that are different from the ones we will pass to this
91 : // function's callee later.
92 576 : params.push_back(__ IntPtrConstant(i + 42));
93 : }
94 : DCHECK_EQ(param_count + 1, params.size());
95 128 : Node* raw_result = tester.raw_assembler_for_testing()->CallN(
96 128 : caller_descriptor, param_count + 1, params.data());
97 256 : __ Return(__ SmiTag(raw_result));
98 128 : return tester.GenerateCodeCloseAndEscape();
99 : }
100 :
101 256 : CallDescriptor* CreateDescriptorForStackArguments(Zone* zone,
102 : int stack_param_count) {
103 : LocationSignature::Builder locations(zone, 1,
104 256 : static_cast<size_t>(stack_param_count));
105 :
106 : locations.AddReturn(LinkageLocation::ForRegister(kReturnRegister0.code(),
107 : MachineType::IntPtr()));
108 :
109 1088 : for (int i = 0; i < stack_param_count; ++i) {
110 416 : locations.AddParam(LinkageLocation::ForCallerFrameSlot(
111 : i - stack_param_count, MachineType::IntPtr()));
112 : }
113 :
114 : return new (zone)
115 : CallDescriptor(CallDescriptor::kCallCodeObject, // kind
116 : MachineType::AnyTagged(), // target MachineType
117 : LinkageLocation::ForAnyRegister(
118 : MachineType::AnyTagged()), // target location
119 : locations.Build(), // location_sig
120 : stack_param_count, // stack_parameter_count
121 : Operator::kNoProperties, // properties
122 : kNoCalleeSaved, // callee-saved registers
123 : kNoCalleeSaved, // callee-saved fp
124 256 : CallDescriptor::kRetpoline); // flags
125 : }
126 :
127 : // Test a tail call from a caller with n parameters to a callee with m
128 : // parameters. All parameters are pointer-sized.
129 128 : void TestHelper(int n, int m, bool tail) {
130 256 : HandleAndZoneScope scope;
131 : Isolate* isolate = scope.main_isolate();
132 256 : CanonicalHandleScope canonical(isolate);
133 : Zone* zone = scope.main_zone();
134 : CallDescriptor* caller_descriptor =
135 128 : CreateDescriptorForStackArguments(zone, n);
136 : CallDescriptor* callee_descriptor =
137 128 : CreateDescriptorForStackArguments(zone, m);
138 : Handle<Code> setup =
139 128 : BuildSetupFunction(isolate, caller_descriptor, callee_descriptor, tail);
140 128 : FunctionTester ft(setup, 0);
141 256 : Handle<Object> result = ft.Call().ToHandleChecked();
142 : int expected = 0;
143 352 : for (int i = 0; i < m; ++i) expected += (i + 1) * i;
144 128 : CHECK_EQ(expected, Handle<Smi>::cast(result)->value());
145 128 : }
146 :
147 : } // namespace
148 :
149 : #undef __
150 :
151 26660 : TEST(RetpolineOddEven) {
152 4 : TestHelper(1, 0, false);
153 4 : TestHelper(1, 2, false);
154 4 : TestHelper(3, 2, false);
155 4 : TestHelper(3, 4, false);
156 4 : }
157 :
158 26660 : TEST(RetpolineOddEvenTail) {
159 4 : TestHelper(1, 0, true);
160 4 : TestHelper(1, 2, true);
161 4 : TestHelper(3, 2, true);
162 4 : TestHelper(3, 4, true);
163 4 : }
164 :
165 26660 : TEST(RetpolineOddOdd) {
166 4 : TestHelper(1, 1, false);
167 4 : TestHelper(1, 3, false);
168 4 : TestHelper(3, 1, false);
169 4 : TestHelper(3, 3, false);
170 4 : }
171 :
172 26660 : TEST(RetpolineOddOddTail) {
173 4 : TestHelper(1, 1, true);
174 4 : TestHelper(1, 3, true);
175 4 : TestHelper(3, 1, true);
176 4 : TestHelper(3, 3, true);
177 4 : }
178 :
179 26660 : TEST(RetpolineEvenEven) {
180 4 : TestHelper(0, 0, false);
181 4 : TestHelper(0, 2, false);
182 4 : TestHelper(2, 0, false);
183 4 : TestHelper(2, 2, false);
184 4 : }
185 :
186 26660 : TEST(RetpolineEvenEvenTail) {
187 4 : TestHelper(0, 0, true);
188 4 : TestHelper(0, 2, true);
189 4 : TestHelper(2, 0, true);
190 4 : TestHelper(2, 2, true);
191 4 : }
192 :
193 26660 : TEST(RetpolineEvenOdd) {
194 4 : TestHelper(0, 1, false);
195 4 : TestHelper(0, 3, false);
196 4 : TestHelper(2, 1, false);
197 4 : TestHelper(2, 3, false);
198 4 : }
199 :
200 26660 : TEST(RetpolineEvenOddTail) {
201 4 : TestHelper(0, 1, true);
202 4 : TestHelper(0, 3, true);
203 4 : TestHelper(2, 1, true);
204 4 : TestHelper(2, 3, true);
205 4 : }
206 :
207 : } // namespace test_run_retpoline
208 : } // namespace compiler
209 : } // namespace internal
210 79968 : } // namespace v8
|