blob: 39af56d5aa1d49a82014cf39768e15b37ab9de80 [file] [log] [blame]
Ben Murdochc5610432016-08-08 18:44:38 +01001// Copyright 2015 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#ifndef V8_COMPILER_CODE_ASSEMBLER_H_
6#define V8_COMPILER_CODE_ASSEMBLER_H_
7
8#include <map>
9
10// Clients of this interface shouldn't depend on lots of compiler internals.
11// Do not include anything from src/compiler here!
12#include "src/allocation.h"
13#include "src/builtins.h"
14#include "src/heap/heap.h"
15#include "src/machine-type.h"
16#include "src/runtime/runtime.h"
17#include "src/zone-containers.h"
18
19namespace v8 {
20namespace internal {
21
22class Callable;
23class CallInterfaceDescriptor;
24class Isolate;
25class Factory;
26class Zone;
27
28namespace compiler {
29
30class CallDescriptor;
31class Graph;
32class Node;
33class Operator;
34class RawMachineAssembler;
35class RawMachineLabel;
36class Schedule;
37
38#define CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \
39 V(Float32Equal) \
40 V(Float32LessThan) \
41 V(Float32LessThanOrEqual) \
42 V(Float32GreaterThan) \
43 V(Float32GreaterThanOrEqual) \
44 V(Float64Equal) \
45 V(Float64LessThan) \
46 V(Float64LessThanOrEqual) \
47 V(Float64GreaterThan) \
48 V(Float64GreaterThanOrEqual) \
49 V(Int32GreaterThan) \
50 V(Int32GreaterThanOrEqual) \
51 V(Int32LessThan) \
52 V(Int32LessThanOrEqual) \
53 V(IntPtrLessThan) \
54 V(IntPtrLessThanOrEqual) \
55 V(IntPtrGreaterThan) \
56 V(IntPtrGreaterThanOrEqual) \
57 V(IntPtrEqual) \
58 V(Uint32LessThan) \
59 V(UintPtrLessThan) \
60 V(UintPtrGreaterThanOrEqual) \
61 V(WordEqual) \
62 V(WordNotEqual) \
63 V(Word32Equal) \
64 V(Word32NotEqual) \
65 V(Word64Equal) \
66 V(Word64NotEqual)
67
68#define CODE_ASSEMBLER_BINARY_OP_LIST(V) \
69 CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \
70 V(Float64Add) \
71 V(Float64Sub) \
72 V(Float64Mul) \
73 V(Float64Div) \
74 V(Float64Mod) \
75 V(Float64InsertLowWord32) \
76 V(Float64InsertHighWord32) \
77 V(IntPtrAdd) \
78 V(IntPtrAddWithOverflow) \
79 V(IntPtrSub) \
80 V(IntPtrSubWithOverflow) \
81 V(IntPtrMul) \
82 V(Int32Add) \
83 V(Int32AddWithOverflow) \
84 V(Int32Sub) \
85 V(Int32Mul) \
86 V(Int32Div) \
87 V(WordOr) \
88 V(WordAnd) \
89 V(WordXor) \
90 V(WordShl) \
91 V(WordShr) \
92 V(WordSar) \
93 V(WordRor) \
94 V(Word32Or) \
95 V(Word32And) \
96 V(Word32Xor) \
97 V(Word32Shl) \
98 V(Word32Shr) \
99 V(Word32Sar) \
100 V(Word32Ror) \
101 V(Word64Or) \
102 V(Word64And) \
103 V(Word64Xor) \
104 V(Word64Shr) \
105 V(Word64Sar) \
106 V(Word64Ror)
107
108#define CODE_ASSEMBLER_UNARY_OP_LIST(V) \
109 V(Float64Neg) \
110 V(Float64Sqrt) \
111 V(Float64ExtractLowWord32) \
112 V(Float64ExtractHighWord32) \
113 V(BitcastWordToTagged) \
114 V(TruncateFloat64ToWord32) \
115 V(TruncateInt64ToInt32) \
116 V(ChangeFloat64ToUint32) \
117 V(ChangeInt32ToFloat64) \
118 V(ChangeInt32ToInt64) \
119 V(ChangeUint32ToFloat64) \
120 V(ChangeUint32ToUint64) \
121 V(RoundFloat64ToInt32) \
122 V(Float64RoundDown) \
123 V(Float64RoundUp) \
124 V(Float64RoundTruncate) \
125 V(Word32Clz)
126
127// A "public" interface used by components outside of compiler directory to
128// create code objects with TurboFan's backend. This class is mostly a thin shim
129// around the RawMachineAssembler, and its primary job is to ensure that the
130// innards of the RawMachineAssembler and other compiler implementation details
131// don't leak outside of the the compiler directory..
132//
133// V8 components that need to generate low-level code using this interface
134// should include this header--and this header only--from the compiler directory
135// (this is actually enforced). Since all interesting data structures are
136// forward declared, it's not possible for clients to peek inside the compiler
137// internals.
138//
139// In addition to providing isolation between TurboFan and code generation
140// clients, CodeAssembler also provides an abstraction for creating variables
141// and enhanced Label functionality to merge variable values along paths where
142// they have differing values, including loops.
143class CodeAssembler {
144 public:
145 // Create with CallStub linkage.
146 // |result_size| specifies the number of results returned by the stub.
147 // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor.
148 CodeAssembler(Isolate* isolate, Zone* zone,
149 const CallInterfaceDescriptor& descriptor, Code::Flags flags,
150 const char* name, size_t result_size = 1);
151
152 // Create with JSCall linkage.
153 CodeAssembler(Isolate* isolate, Zone* zone, int parameter_count,
154 Code::Flags flags, const char* name);
155
156 virtual ~CodeAssembler();
157
158 Handle<Code> GenerateCode();
159
160 bool Is64() const;
161 bool IsFloat64RoundUpSupported() const;
162 bool IsFloat64RoundDownSupported() const;
163 bool IsFloat64RoundTruncateSupported() const;
164
165 class Label;
166 class Variable {
167 public:
168 explicit Variable(CodeAssembler* assembler, MachineRepresentation rep);
169 void Bind(Node* value);
170 Node* value() const;
171 MachineRepresentation rep() const;
172 bool IsBound() const;
173
174 private:
175 friend class CodeAssembler;
176 class Impl;
177 Impl* impl_;
178 };
179
180 enum AllocationFlag : uint8_t {
181 kNone = 0,
182 kDoubleAlignment = 1,
183 kPretenured = 1 << 1
184 };
185
186 typedef base::Flags<AllocationFlag> AllocationFlags;
187
188 // ===========================================================================
189 // Base Assembler
190 // ===========================================================================
191
192 // Constants.
193 Node* Int32Constant(int32_t value);
194 Node* Int64Constant(int64_t value);
195 Node* IntPtrConstant(intptr_t value);
196 Node* NumberConstant(double value);
197 Node* SmiConstant(Smi* value);
198 Node* HeapConstant(Handle<HeapObject> object);
199 Node* BooleanConstant(bool value);
200 Node* ExternalConstant(ExternalReference address);
201 Node* Float64Constant(double value);
202 Node* NaNConstant();
203
204 bool ToInt32Constant(Node* node, int32_t& out_value);
205 bool ToInt64Constant(Node* node, int64_t& out_value);
206 bool ToIntPtrConstant(Node* node, intptr_t& out_value);
207
208 Node* Parameter(int value);
209 void Return(Node* value);
210
211 void Bind(Label* label);
212 void Goto(Label* label);
213 void GotoIf(Node* condition, Label* true_label);
214 void GotoUnless(Node* condition, Label* false_label);
215 void Branch(Node* condition, Label* true_label, Label* false_label);
216
217 void Switch(Node* index, Label* default_label, int32_t* case_values,
218 Label** case_labels, size_t case_count);
219
220 // Access to the frame pointer
221 Node* LoadFramePointer();
222 Node* LoadParentFramePointer();
223
224 // Access to the stack pointer
225 Node* LoadStackPointer();
226
227 // Load raw memory location.
228 Node* Load(MachineType rep, Node* base);
229 Node* Load(MachineType rep, Node* base, Node* index);
230 Node* AtomicLoad(MachineType rep, Node* base, Node* index);
231
232 // Load a value from the root array.
233 Node* LoadRoot(Heap::RootListIndex root_index);
234
235 // Store value to raw memory location.
236 Node* Store(MachineRepresentation rep, Node* base, Node* value);
237 Node* Store(MachineRepresentation rep, Node* base, Node* index, Node* value);
238 Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* value);
239 Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* index,
240 Node* value);
241 Node* AtomicStore(MachineRepresentation rep, Node* base, Node* index,
242 Node* value);
243
244 // Store a value to the root array.
245 Node* StoreRoot(Heap::RootListIndex root_index, Node* value);
246
247// Basic arithmetic operations.
248#define DECLARE_CODE_ASSEMBLER_BINARY_OP(name) Node* name(Node* a, Node* b);
249 CODE_ASSEMBLER_BINARY_OP_LIST(DECLARE_CODE_ASSEMBLER_BINARY_OP)
250#undef DECLARE_CODE_ASSEMBLER_BINARY_OP
251
252 Node* WordShl(Node* value, int shift);
253 Node* WordShr(Node* value, int shift);
254
255// Unary
256#define DECLARE_CODE_ASSEMBLER_UNARY_OP(name) Node* name(Node* a);
257 CODE_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_ASSEMBLER_UNARY_OP)
258#undef DECLARE_CODE_ASSEMBLER_UNARY_OP
259
260 // No-op on 32-bit, otherwise zero extend.
261 Node* ChangeUint32ToWord(Node* value);
262 // No-op on 32-bit, otherwise sign extend.
263 Node* ChangeInt32ToIntPtr(Node* value);
264
265 // Projections
266 Node* Projection(int index, Node* value);
267
268 // Calls
269 Node* CallRuntime(Runtime::FunctionId function_id, Node* context);
270 Node* CallRuntime(Runtime::FunctionId function_id, Node* context, Node* arg1);
271 Node* CallRuntime(Runtime::FunctionId function_id, Node* context, Node* arg1,
272 Node* arg2);
273 Node* CallRuntime(Runtime::FunctionId function_id, Node* context, Node* arg1,
274 Node* arg2, Node* arg3);
275 Node* CallRuntime(Runtime::FunctionId function_id, Node* context, Node* arg1,
276 Node* arg2, Node* arg3, Node* arg4);
277 Node* CallRuntime(Runtime::FunctionId function_id, Node* context, Node* arg1,
278 Node* arg2, Node* arg3, Node* arg4, Node* arg5);
279
280 Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context);
281 Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context,
282 Node* arg1);
283 Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context,
284 Node* arg1, Node* arg2);
285 Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context,
286 Node* arg1, Node* arg2, Node* arg3);
287 Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context,
288 Node* arg1, Node* arg2, Node* arg3, Node* arg4);
289
290 Node* CallStub(Callable const& callable, Node* context, Node* arg1,
291 size_t result_size = 1);
292 Node* CallStub(Callable const& callable, Node* context, Node* arg1,
293 Node* arg2, size_t result_size = 1);
294 Node* CallStub(Callable const& callable, Node* context, Node* arg1,
295 Node* arg2, Node* arg3, size_t result_size = 1);
296
297 Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
298 Node* context, Node* arg1, size_t result_size = 1);
299 Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
300 Node* context, Node* arg1, Node* arg2, size_t result_size = 1);
301 Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
302 Node* context, Node* arg1, Node* arg2, Node* arg3,
303 size_t result_size = 1);
304 Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
305 Node* context, Node* arg1, Node* arg2, Node* arg3, Node* arg4,
306 size_t result_size = 1);
307 Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
308 Node* context, Node* arg1, Node* arg2, Node* arg3, Node* arg4,
309 Node* arg5, size_t result_size = 1);
310
311 Node* TailCallStub(Callable const& callable, Node* context, Node* arg1,
312 Node* arg2, size_t result_size = 1);
313 Node* TailCallStub(Callable const& callable, Node* context, Node* arg1,
314 Node* arg2, Node* arg3, size_t result_size = 1);
315 Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
316 Node* context, Node* arg1, Node* arg2,
317 size_t result_size = 1);
318 Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
319 Node* context, Node* arg1, Node* arg2, Node* arg3,
320 size_t result_size = 1);
321
322 Node* TailCallBytecodeDispatch(const CallInterfaceDescriptor& descriptor,
323 Node* code_target_address, Node** args);
324
325 // Branching helpers.
326 void BranchIf(Node* condition, Label* if_true, Label* if_false);
327
328#define BRANCH_HELPER(name) \
329 void BranchIf##name(Node* a, Node* b, Label* if_true, Label* if_false) { \
330 BranchIf(name(a, b), if_true, if_false); \
331 }
332 CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(BRANCH_HELPER)
333#undef BRANCH_HELPER
334
335 // Helpers which delegate to RawMachineAssembler.
336 Factory* factory() const;
337 Isolate* isolate() const;
338 Zone* zone() const;
339
340 protected:
341 // Protected helpers which delegate to RawMachineAssembler.
342 Graph* graph() const;
343
344 Node* SmiShiftBitsConstant();
345
346 // Enables subclasses to perform operations before and after a call.
347 virtual void CallPrologue();
348 virtual void CallEpilogue();
349
350 private:
351 friend class CodeAssemblerTester;
352
353 CodeAssembler(Isolate* isolate, Zone* zone, CallDescriptor* call_descriptor,
354 Code::Flags flags, const char* name);
355
356 Node* CallN(CallDescriptor* descriptor, Node* code_target, Node** args);
357 Node* TailCallN(CallDescriptor* descriptor, Node* code_target, Node** args);
358
359 base::SmartPointer<RawMachineAssembler> raw_assembler_;
360 Code::Flags flags_;
361 const char* name_;
362 bool code_generated_;
363 ZoneVector<Variable::Impl*> variables_;
364
365 DISALLOW_COPY_AND_ASSIGN(CodeAssembler);
366};
367
368DEFINE_OPERATORS_FOR_FLAGS(CodeAssembler::AllocationFlags);
369
370class CodeAssembler::Label {
371 public:
372 enum Type { kDeferred, kNonDeferred };
373
374 explicit Label(
375 CodeAssembler* assembler,
376 CodeAssembler::Label::Type type = CodeAssembler::Label::kNonDeferred)
377 : CodeAssembler::Label(assembler, 0, nullptr, type) {}
378 Label(CodeAssembler* assembler, CodeAssembler::Variable* merged_variable,
379 CodeAssembler::Label::Type type = CodeAssembler::Label::kNonDeferred)
380 : CodeAssembler::Label(assembler, 1, &merged_variable, type) {}
381 Label(CodeAssembler* assembler, int merged_variable_count,
382 CodeAssembler::Variable** merged_variables,
383 CodeAssembler::Label::Type type = CodeAssembler::Label::kNonDeferred);
384 ~Label() {}
385
386 private:
387 friend class CodeAssembler;
388
389 void Bind();
390 void MergeVariables();
391
392 bool bound_;
393 size_t merge_count_;
394 CodeAssembler* assembler_;
395 RawMachineLabel* label_;
396 // Map of variables that need to be merged to their phi nodes (or placeholders
397 // for those phis).
398 std::map<Variable::Impl*, Node*> variable_phis_;
399 // Map of variables to the list of value nodes that have been added from each
400 // merge path in their order of merging.
401 std::map<Variable::Impl*, std::vector<Node*>> variable_merges_;
402};
403
404} // namespace compiler
405} // namespace internal
406} // namespace v8
407
408#endif // V8_COMPILER_CODE_ASSEMBLER_H_