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