1 // Copyright 2016 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_GRAPH_ASSEMBLER_H_ 6 #define V8_COMPILER_GRAPH_ASSEMBLER_H_ 7 8 #include "src/compiler/js-graph.h" 9 #include "src/compiler/node.h" 10 #include "src/compiler/simplified-operator.h" 11 #include "src/vector-slot-pair.h" 12 13 namespace v8 { 14 namespace internal { 15 16 class JSGraph; 17 class Graph; 18 19 namespace compiler { 20 21 #define PURE_ASSEMBLER_MACH_UNOP_LIST(V) \ 22 V(ChangeInt32ToInt64) \ 23 V(ChangeInt32ToFloat64) \ 24 V(ChangeUint32ToFloat64) \ 25 V(ChangeUint32ToUint64) \ 26 V(ChangeFloat64ToInt32) \ 27 V(ChangeFloat64ToUint32) \ 28 V(TruncateInt64ToInt32) \ 29 V(RoundFloat64ToInt32) \ 30 V(TruncateFloat64ToWord32) \ 31 V(Float64ExtractLowWord32) \ 32 V(Float64ExtractHighWord32) \ 33 V(BitcastInt32ToFloat32) \ 34 V(BitcastInt64ToFloat64) \ 35 V(BitcastFloat32ToInt32) \ 36 V(BitcastFloat64ToInt64) \ 37 V(Float64Abs) \ 38 V(Word32ReverseBytes) \ 39 V(Word64ReverseBytes) 40 41 #define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \ 42 V(WordShl) \ 43 V(WordSar) \ 44 V(WordAnd) \ 45 V(Word32Or) \ 46 V(Word32And) \ 47 V(Word32Xor) \ 48 V(Word32Shr) \ 49 V(Word32Shl) \ 50 V(Word32Sar) \ 51 V(IntAdd) \ 52 V(IntSub) \ 53 V(IntMul) \ 54 V(IntLessThan) \ 55 V(UintLessThan) \ 56 V(Int32Add) \ 57 V(Int32Sub) \ 58 V(Int32Mul) \ 59 V(Int32LessThanOrEqual) \ 60 V(Uint32LessThanOrEqual) \ 61 V(Uint32LessThan) \ 62 V(Int32LessThan) \ 63 V(Float64Add) \ 64 V(Float64Sub) \ 65 V(Float64Div) \ 66 V(Float64Mod) \ 67 V(Float64Equal) \ 68 V(Float64LessThan) \ 69 V(Float64LessThanOrEqual) \ 70 V(Float64InsertLowWord32) \ 71 V(Float64InsertHighWord32) \ 72 V(Word32Equal) \ 73 V(WordEqual) 74 75 #define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \ 76 V(Int32AddWithOverflow) \ 77 V(Int32SubWithOverflow) \ 78 V(Int32MulWithOverflow) \ 79 V(Int32Mod) \ 80 V(Int32Div) \ 81 V(Uint32Mod) \ 82 V(Uint32Div) 83 84 #define JSGRAPH_SINGLETON_CONSTANT_LIST(V) \ 85 V(TrueConstant) \ 86 V(FalseConstant) \ 87 V(NullConstant) \ 88 V(HeapNumberMapConstant) \ 89 V(NoContextConstant) \ 90 V(EmptyStringConstant) \ 91 V(UndefinedConstant) \ 92 V(TheHoleConstant) \ 93 V(FixedArrayMapConstant) \ 94 V(FixedDoubleArrayMapConstant) \ 95 V(ToNumberBuiltinConstant) \ 96 V(AllocateInNewSpaceStubConstant) \ 97 V(AllocateInOldSpaceStubConstant) 98 99 class GraphAssembler; 100 101 enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop }; 102 103 // Label with statically known count of incoming branches and phis. 104 template <size_t VarCount> 105 class GraphAssemblerLabel { 106 public: 107 Node* PhiAt(size_t index); 108 109 template <typename... Reps> 110 explicit GraphAssemblerLabel(GraphAssemblerLabelType type, Reps... reps) 111 : type_(type) { 112 STATIC_ASSERT(VarCount == sizeof...(reps)); 113 MachineRepresentation reps_array[] = {MachineRepresentation::kNone, 114 reps...}; 115 for (size_t i = 0; i < VarCount; i++) { 116 representations_[i] = reps_array[i + 1]; 117 } 118 } 119 120 ~GraphAssemblerLabel() { DCHECK(IsBound() || merged_count_ == 0); } 121 122 private: 123 friend class GraphAssembler; 124 125 void SetBound() { 126 DCHECK(!IsBound()); 127 is_bound_ = true; 128 } 129 bool IsBound() const { return is_bound_; } 130 bool IsDeferred() const { 131 return type_ == GraphAssemblerLabelType::kDeferred; 132 } 133 bool IsLoop() const { return type_ == GraphAssemblerLabelType::kLoop; } 134 135 bool is_bound_ = false; 136 GraphAssemblerLabelType const type_; 137 size_t merged_count_ = 0; 138 Node* effect_; 139 Node* control_; 140 Node* bindings_[VarCount + 1]; 141 MachineRepresentation representations_[VarCount + 1]; 142 }; 143 144 class GraphAssembler { 145 public: 146 GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone); 147 148 void Reset(Node* effect, Node* control); 149 150 // Create label. 151 template <typename... Reps> 152 static GraphAssemblerLabel<sizeof...(Reps)> MakeLabelFor( 153 GraphAssemblerLabelType type, Reps... reps) { 154 return GraphAssemblerLabel<sizeof...(Reps)>(type, reps...); 155 } 156 157 // Convenience wrapper for creating non-deferred labels. 158 template <typename... Reps> 159 static GraphAssemblerLabel<sizeof...(Reps)> MakeLabel(Reps... reps) { 160 return MakeLabelFor(GraphAssemblerLabelType::kNonDeferred, reps...); 161 } 162 163 // Convenience wrapper for creating loop labels. 164 template <typename... Reps> 165 static GraphAssemblerLabel<sizeof...(Reps)> MakeLoopLabel(Reps... reps) { 166 return MakeLabelFor(GraphAssemblerLabelType::kLoop, reps...); 167 } 168 169 // Convenience wrapper for creating deferred labels. 170 template <typename... Reps> 171 static GraphAssemblerLabel<sizeof...(Reps)> MakeDeferredLabel(Reps... reps) { 172 return MakeLabelFor(GraphAssemblerLabelType::kDeferred, reps...); 173 } 174 175 // Value creation. 176 Node* IntPtrConstant(intptr_t value); 177 Node* Uint32Constant(int32_t value); 178 Node* Int32Constant(int32_t value); 179 Node* UniqueInt32Constant(int32_t value); 180 Node* SmiConstant(int32_t value); 181 Node* Float64Constant(double value); 182 Node* Projection(int index, Node* value); 183 Node* HeapConstant(Handle<HeapObject> object); 184 Node* CEntryStubConstant(int result_size); 185 Node* ExternalConstant(ExternalReference ref); 186 187 Node* LoadFramePointer(); 188 189 #define SINGLETON_CONST_DECL(Name) Node* Name(); 190 JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL) 191 #undef SINGLETON_CONST_DECL 192 193 #define PURE_UNOP_DECL(Name) Node* Name(Node* input); 194 PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL) 195 #undef PURE_UNOP_DECL 196 197 #define BINOP_DECL(Name) Node* Name(Node* left, Node* right); 198 PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL) 199 CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL) 200 #undef BINOP_DECL 201 202 // Debugging 203 Node* DebugBreak(); 204 205 Node* Unreachable(); 206 207 Node* Float64RoundDown(Node* value); 208 Node* Float64RoundTruncate(Node* value); 209 210 Node* ToNumber(Node* value); 211 Node* BitcastWordToTagged(Node* value); 212 Node* Allocate(PretenureFlag pretenure, Node* size); 213 Node* LoadField(FieldAccess const&, Node* object); 214 Node* LoadElement(ElementAccess const&, Node* object, Node* index); 215 Node* StoreField(FieldAccess const&, Node* object, Node* value); 216 Node* StoreElement(ElementAccess const&, Node* object, Node* index, 217 Node* value); 218 219 Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value); 220 Node* Load(MachineType rep, Node* object, Node* offset); 221 222 Node* StoreUnaligned(MachineRepresentation rep, Node* object, Node* offset, 223 Node* value); 224 Node* LoadUnaligned(MachineType rep, Node* object, Node* offset); 225 226 Node* Retain(Node* buffer); 227 Node* UnsafePointerAdd(Node* base, Node* external); 228 229 Node* Word32PoisonOnSpeculation(Node* value); 230 231 Node* DeoptimizeIf(DeoptimizeReason reason, VectorSlotPair const& feedback, 232 Node* condition, Node* frame_state); 233 Node* DeoptimizeIfNot( 234 DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition, 235 Node* frame_state, 236 IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck); 237 template <typename... Args> 238 Node* Call(const CallDescriptor* call_descriptor, Args... args); 239 template <typename... Args> 240 Node* Call(const Operator* op, Args... args); 241 242 // Basic control operations. 243 template <size_t VarCount> 244 void Bind(GraphAssemblerLabel<VarCount>* label); 245 246 template <typename... Vars> 247 void Goto(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars...); 248 249 void Branch(Node* condition, GraphAssemblerLabel<0u>* if_true, 250 GraphAssemblerLabel<0u>* if_false); 251 252 // Control helpers. 253 // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}. 254 template <typename... Vars> 255 void GotoIf(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label, 256 Vars...); 257 258 // {GotoIfNot(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}. 259 template <typename... Vars> 260 void GotoIfNot(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label, 261 Vars...); 262 263 // Extractors (should be only used when destructing/resetting the assembler). 264 Node* ExtractCurrentControl(); 265 Node* ExtractCurrentEffect(); 266 267 private: 268 template <typename... Vars> 269 void MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars... vars); 270 271 Operator const* ToNumberOperator(); 272 273 JSGraph* jsgraph() const { return jsgraph_; } 274 Isolate* isolate() const { return jsgraph_->isolate(); } 275 Graph* graph() const { return jsgraph_->graph(); } 276 Zone* temp_zone() const { return temp_zone_; } 277 CommonOperatorBuilder* common() const { return jsgraph()->common(); } 278 MachineOperatorBuilder* machine() const { return jsgraph()->machine(); } 279 SimplifiedOperatorBuilder* simplified() const { 280 return jsgraph()->simplified(); 281 } 282 283 SetOncePointer<Operator const> to_number_operator_; 284 Zone* temp_zone_; 285 JSGraph* jsgraph_; 286 Node* current_effect_; 287 Node* current_control_; 288 }; 289 290 template <size_t VarCount> 291 Node* GraphAssemblerLabel<VarCount>::PhiAt(size_t index) { 292 DCHECK(IsBound()); 293 DCHECK_LT(index, VarCount); 294 return bindings_[index]; 295 } 296 297 template <typename... Vars> 298 void GraphAssembler::MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label, 299 Vars... vars) { 300 int merged_count = static_cast<int>(label->merged_count_); 301 Node* var_array[] = {nullptr, vars...}; 302 if (label->IsLoop()) { 303 if (merged_count == 0) { 304 DCHECK(!label->IsBound()); 305 label->control_ = graph()->NewNode(common()->Loop(2), current_control_, 306 current_control_); 307 label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_, 308 current_effect_, label->control_); 309 Node* terminate = graph()->NewNode(common()->Terminate(), label->effect_, 310 label->control_); 311 NodeProperties::MergeControlToEnd(graph(), common(), terminate); 312 for (size_t i = 0; i < sizeof...(vars); i++) { 313 label->bindings_[i] = graph()->NewNode( 314 common()->Phi(label->representations_[i], 2), var_array[i + 1], 315 var_array[i + 1], label->control_); 316 } 317 } else { 318 DCHECK(label->IsBound()); 319 DCHECK_EQ(1, merged_count); 320 label->control_->ReplaceInput(1, current_control_); 321 label->effect_->ReplaceInput(1, current_effect_); 322 for (size_t i = 0; i < sizeof...(vars); i++) { 323 label->bindings_[i]->ReplaceInput(1, var_array[i + 1]); 324 } 325 } 326 } else { 327 DCHECK(!label->IsBound()); 328 if (merged_count == 0) { 329 // Just set the control, effect and variables directly. 330 DCHECK(!label->IsBound()); 331 label->control_ = current_control_; 332 label->effect_ = current_effect_; 333 for (size_t i = 0; i < sizeof...(vars); i++) { 334 label->bindings_[i] = var_array[i + 1]; 335 } 336 } else if (merged_count == 1) { 337 // Create merge, effect phi and a phi for each variable. 338 label->control_ = graph()->NewNode(common()->Merge(2), label->control_, 339 current_control_); 340 label->effect_ = graph()->NewNode(common()->EffectPhi(2), label->effect_, 341 current_effect_, label->control_); 342 for (size_t i = 0; i < sizeof...(vars); i++) { 343 label->bindings_[i] = graph()->NewNode( 344 common()->Phi(label->representations_[i], 2), label->bindings_[i], 345 var_array[i + 1], label->control_); 346 } 347 } else { 348 // Append to the merge, effect phi and phis. 349 DCHECK_EQ(IrOpcode::kMerge, label->control_->opcode()); 350 label->control_->AppendInput(graph()->zone(), current_control_); 351 NodeProperties::ChangeOp(label->control_, 352 common()->Merge(merged_count + 1)); 353 354 DCHECK_EQ(IrOpcode::kEffectPhi, label->effect_->opcode()); 355 label->effect_->ReplaceInput(merged_count, current_effect_); 356 label->effect_->AppendInput(graph()->zone(), label->control_); 357 NodeProperties::ChangeOp(label->effect_, 358 common()->EffectPhi(merged_count + 1)); 359 360 for (size_t i = 0; i < sizeof...(vars); i++) { 361 DCHECK_EQ(IrOpcode::kPhi, label->bindings_[i]->opcode()); 362 label->bindings_[i]->ReplaceInput(merged_count, var_array[i + 1]); 363 label->bindings_[i]->AppendInput(graph()->zone(), label->control_); 364 NodeProperties::ChangeOp( 365 label->bindings_[i], 366 common()->Phi(label->representations_[i], merged_count + 1)); 367 } 368 } 369 } 370 label->merged_count_++; 371 } 372 373 template <size_t VarCount> 374 void GraphAssembler::Bind(GraphAssemblerLabel<VarCount>* label) { 375 DCHECK_NULL(current_control_); 376 DCHECK_NULL(current_effect_); 377 DCHECK_LT(0, label->merged_count_); 378 379 current_control_ = label->control_; 380 current_effect_ = label->effect_; 381 382 label->SetBound(); 383 } 384 385 template <typename... Vars> 386 void GraphAssembler::Goto(GraphAssemblerLabel<sizeof...(Vars)>* label, 387 Vars... vars) { 388 DCHECK_NOT_NULL(current_control_); 389 DCHECK_NOT_NULL(current_effect_); 390 MergeState(label, vars...); 391 current_control_ = nullptr; 392 current_effect_ = nullptr; 393 } 394 395 template <typename... Vars> 396 void GraphAssembler::GotoIf(Node* condition, 397 GraphAssemblerLabel<sizeof...(Vars)>* label, 398 Vars... vars) { 399 BranchHint hint = 400 label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone; 401 Node* branch = 402 graph()->NewNode(common()->Branch(hint), condition, current_control_); 403 404 current_control_ = graph()->NewNode(common()->IfTrue(), branch); 405 MergeState(label, vars...); 406 407 current_control_ = graph()->NewNode(common()->IfFalse(), branch); 408 } 409 410 template <typename... Vars> 411 void GraphAssembler::GotoIfNot(Node* condition, 412 GraphAssemblerLabel<sizeof...(Vars)>* label, 413 Vars... vars) { 414 BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone; 415 Node* branch = 416 graph()->NewNode(common()->Branch(hint), condition, current_control_); 417 418 current_control_ = graph()->NewNode(common()->IfFalse(), branch); 419 MergeState(label, vars...); 420 421 current_control_ = graph()->NewNode(common()->IfTrue(), branch); 422 } 423 424 template <typename... Args> 425 Node* GraphAssembler::Call(const CallDescriptor* call_descriptor, 426 Args... args) { 427 const Operator* op = common()->Call(call_descriptor); 428 return Call(op, args...); 429 } 430 431 template <typename... Args> 432 Node* GraphAssembler::Call(const Operator* op, Args... args) { 433 DCHECK_EQ(IrOpcode::kCall, op->opcode()); 434 Node* args_array[] = {args..., current_effect_, current_control_}; 435 int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() + 436 op->ControlInputCount(); 437 Node* call = graph()->NewNode(op, size, args_array); 438 DCHECK_EQ(0, op->ControlOutputCount()); 439 current_effect_ = call; 440 return call; 441 } 442 443 } // namespace compiler 444 } // namespace internal 445 } // namespace v8 446 447 #endif // V8_COMPILER_GRAPH_ASSEMBLER_H_ 448