| OLD | NEW |
| 1 //===- subzero/src/IceInst.h - High-level instructions ----------*- C++ -*-===// | 1 //===- subzero/src/IceInst.h - High-level instructions ----------*- C++ -*-===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 virtual bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) { | 128 virtual bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
| 129 (void)OldNode; | 129 (void)OldNode; |
| 130 (void)NewNode; | 130 (void)NewNode; |
| 131 return false; | 131 return false; |
| 132 } | 132 } |
| 133 | 133 |
| 134 /// Returns true if the instruction is equivalent to a simple | 134 /// Returns true if the instruction is equivalent to a simple |
| 135 /// "var_dest=var_src" assignment where the dest and src are both variables. | 135 /// "var_dest=var_src" assignment where the dest and src are both variables. |
| 136 virtual bool isVarAssign() const { return false; } | 136 virtual bool isVarAssign() const { return false; } |
| 137 | 137 |
| 138 /// Returns true if the instruction has a possible side effect of changing |
| 139 /// memory, in which case a memory load should not be reordered with respect |
| 140 /// to this instruction. It should really be pure virtual, but we can't |
| 141 /// because of g++ and llvm::ilist<>, so we implement it as |
| 142 /// report_fatal_error(). |
| 143 virtual bool isMemoryWrite() const; |
| 144 |
| 138 void livenessLightweight(Cfg *Func, LivenessBV &Live); | 145 void livenessLightweight(Cfg *Func, LivenessBV &Live); |
| 139 /// Calculates liveness for this instruction. Returns true if this instruction | 146 /// Calculates liveness for this instruction. Returns true if this instruction |
| 140 /// is (tentatively) still live and should be retained, and false if this | 147 /// is (tentatively) still live and should be retained, and false if this |
| 141 /// instruction is (tentatively) dead and should be deleted. The decision is | 148 /// instruction is (tentatively) dead and should be deleted. The decision is |
| 142 /// tentative until the liveness dataflow algorithm has converged, and then a | 149 /// tentative until the liveness dataflow algorithm has converged, and then a |
| 143 /// separate pass permanently deletes dead instructions. | 150 /// separate pass permanently deletes dead instructions. |
| 144 bool liveness(InstNumberT InstNumber, LivenessBV &Live, Liveness *Liveness, | 151 bool liveness(InstNumberT InstNumber, LivenessBV &Live, Liveness *Liveness, |
| 145 LiveBeginEndMap *LiveBegin, LiveBeginEndMap *LiveEnd); | 152 LiveBeginEndMap *LiveBegin, LiveBeginEndMap *LiveEnd); |
| 146 | 153 |
| 147 /// Get the number of native instructions that this instruction ultimately | 154 /// Get the number of native instructions that this instruction ultimately |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 public: | 259 public: |
| 253 static InstAlloca *create(Cfg *Func, Variable *Dest, Operand *ByteCount, | 260 static InstAlloca *create(Cfg *Func, Variable *Dest, Operand *ByteCount, |
| 254 uint32_t AlignInBytes) { | 261 uint32_t AlignInBytes) { |
| 255 return new (Func->allocate<InstAlloca>()) | 262 return new (Func->allocate<InstAlloca>()) |
| 256 InstAlloca(Func, Dest, ByteCount, AlignInBytes); | 263 InstAlloca(Func, Dest, ByteCount, AlignInBytes); |
| 257 } | 264 } |
| 258 uint32_t getAlignInBytes() const { return AlignInBytes; } | 265 uint32_t getAlignInBytes() const { return AlignInBytes; } |
| 259 Operand *getSizeInBytes() const { return getSrc(0); } | 266 Operand *getSizeInBytes() const { return getSrc(0); } |
| 260 bool getKnownFrameOffset() const { return KnownFrameOffset; } | 267 bool getKnownFrameOffset() const { return KnownFrameOffset; } |
| 261 void setKnownFrameOffset() { KnownFrameOffset = true; } | 268 void setKnownFrameOffset() { KnownFrameOffset = true; } |
| 269 bool isMemoryWrite() const override { return false; } |
| 262 void dump(const Cfg *Func) const override; | 270 void dump(const Cfg *Func) const override; |
| 263 static bool classof(const Inst *Instr) { return Instr->getKind() == Alloca; } | 271 static bool classof(const Inst *Instr) { return Instr->getKind() == Alloca; } |
| 264 | 272 |
| 265 private: | 273 private: |
| 266 InstAlloca(Cfg *Func, Variable *Dest, Operand *ByteCount, | 274 InstAlloca(Cfg *Func, Variable *Dest, Operand *ByteCount, |
| 267 uint32_t AlignInBytes); | 275 uint32_t AlignInBytes); |
| 268 | 276 |
| 269 const uint32_t AlignInBytes; | 277 const uint32_t AlignInBytes; |
| 270 bool KnownFrameOffset = false; | 278 bool KnownFrameOffset = false; |
| 271 }; | 279 }; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 289 Operand *Source1, Operand *Source2) { | 297 Operand *Source1, Operand *Source2) { |
| 290 return new (Func->allocate<InstArithmetic>()) | 298 return new (Func->allocate<InstArithmetic>()) |
| 291 InstArithmetic(Func, Op, Dest, Source1, Source2); | 299 InstArithmetic(Func, Op, Dest, Source1, Source2); |
| 292 } | 300 } |
| 293 OpKind getOp() const { return Op; } | 301 OpKind getOp() const { return Op; } |
| 294 | 302 |
| 295 virtual const char *getInstName() const override; | 303 virtual const char *getInstName() const override; |
| 296 | 304 |
| 297 static const char *getOpName(OpKind Op); | 305 static const char *getOpName(OpKind Op); |
| 298 bool isCommutative() const; | 306 bool isCommutative() const; |
| 307 bool isMemoryWrite() const override { return false; } |
| 299 void dump(const Cfg *Func) const override; | 308 void dump(const Cfg *Func) const override; |
| 300 static bool classof(const Inst *Instr) { | 309 static bool classof(const Inst *Instr) { |
| 301 return Instr->getKind() == Arithmetic; | 310 return Instr->getKind() == Arithmetic; |
| 302 } | 311 } |
| 303 | 312 |
| 304 private: | 313 private: |
| 305 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1, | 314 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1, |
| 306 Operand *Source2); | 315 Operand *Source2); |
| 307 | 316 |
| 308 const OpKind Op; | 317 const OpKind Op; |
| 309 }; | 318 }; |
| 310 | 319 |
| 311 /// Assignment instruction. The source operand is captured in getSrc(0). This is | 320 /// Assignment instruction. The source operand is captured in getSrc(0). This is |
| 312 /// not part of the LLVM bitcode, but is a useful abstraction for some of the | 321 /// not part of the LLVM bitcode, but is a useful abstraction for some of the |
| 313 /// lowering. E.g., if Phi instruction lowering happens before target lowering, | 322 /// lowering. E.g., if Phi instruction lowering happens before target lowering, |
| 314 /// or for representing an Inttoptr instruction, or as an intermediate step for | 323 /// or for representing an Inttoptr instruction, or as an intermediate step for |
| 315 /// lowering a Load instruction. | 324 /// lowering a Load instruction. |
| 316 class InstAssign : public InstHighLevel { | 325 class InstAssign : public InstHighLevel { |
| 317 InstAssign() = delete; | 326 InstAssign() = delete; |
| 318 InstAssign(const InstAssign &) = delete; | 327 InstAssign(const InstAssign &) = delete; |
| 319 InstAssign &operator=(const InstAssign &) = delete; | 328 InstAssign &operator=(const InstAssign &) = delete; |
| 320 | 329 |
| 321 public: | 330 public: |
| 322 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) { | 331 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) { |
| 323 return new (Func->allocate<InstAssign>()) InstAssign(Func, Dest, Source); | 332 return new (Func->allocate<InstAssign>()) InstAssign(Func, Dest, Source); |
| 324 } | 333 } |
| 325 bool isVarAssign() const override; | 334 bool isVarAssign() const override; |
| 335 bool isMemoryWrite() const override { return false; } |
| 326 void dump(const Cfg *Func) const override; | 336 void dump(const Cfg *Func) const override; |
| 327 static bool classof(const Inst *Instr) { return Instr->getKind() == Assign; } | 337 static bool classof(const Inst *Instr) { return Instr->getKind() == Assign; } |
| 328 | 338 |
| 329 private: | 339 private: |
| 330 InstAssign(Cfg *Func, Variable *Dest, Operand *Source); | 340 InstAssign(Cfg *Func, Variable *Dest, Operand *Source); |
| 331 }; | 341 }; |
| 332 | 342 |
| 333 /// Branch instruction. This represents both conditional and unconditional | 343 /// Branch instruction. This represents both conditional and unconditional |
| 334 /// branches. | 344 /// branches. |
| 335 class InstBr : public InstHighLevel { | 345 class InstBr : public InstHighLevel { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 356 } | 366 } |
| 357 CfgNode *getTargetTrue() const { return TargetTrue; } | 367 CfgNode *getTargetTrue() const { return TargetTrue; } |
| 358 CfgNode *getTargetFalse() const { return TargetFalse; } | 368 CfgNode *getTargetFalse() const { return TargetFalse; } |
| 359 CfgNode *getTargetUnconditional() const { | 369 CfgNode *getTargetUnconditional() const { |
| 360 assert(isUnconditional()); | 370 assert(isUnconditional()); |
| 361 return getTargetFalse(); | 371 return getTargetFalse(); |
| 362 } | 372 } |
| 363 NodeList getTerminatorEdges() const override; | 373 NodeList getTerminatorEdges() const override; |
| 364 bool isUnconditionalBranch() const override { return isUnconditional(); } | 374 bool isUnconditionalBranch() const override { return isUnconditional(); } |
| 365 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; | 375 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; |
| 376 bool isMemoryWrite() const override { return false; } |
| 366 void dump(const Cfg *Func) const override; | 377 void dump(const Cfg *Func) const override; |
| 367 static bool classof(const Inst *Instr) { return Instr->getKind() == Br; } | 378 static bool classof(const Inst *Instr) { return Instr->getKind() == Br; } |
| 368 | 379 |
| 369 private: | 380 private: |
| 370 /// Conditional branch | 381 /// Conditional branch |
| 371 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse); | 382 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse); |
| 372 /// Unconditional branch | 383 /// Unconditional branch |
| 373 InstBr(Cfg *Func, CfgNode *Target); | 384 InstBr(Cfg *Func, CfgNode *Target); |
| 374 | 385 |
| 375 CfgNode *TargetFalse; /// Doubles as unconditional branch target | 386 CfgNode *TargetFalse; /// Doubles as unconditional branch target |
| (...skipping 19 matching lines...) Expand all Loading... |
| 395 return new (Func->allocate<InstCall>()) | 406 return new (Func->allocate<InstCall>()) |
| 396 InstCall(Func, NumArgs, Dest, CallTarget, HasTailCall, | 407 InstCall(Func, NumArgs, Dest, CallTarget, HasTailCall, |
| 397 IsTargetHelperCall, HasSideEffects, Kind); | 408 IsTargetHelperCall, HasSideEffects, Kind); |
| 398 } | 409 } |
| 399 void addArg(Operand *Arg) { addSource(Arg); } | 410 void addArg(Operand *Arg) { addSource(Arg); } |
| 400 Operand *getCallTarget() const { return getSrc(0); } | 411 Operand *getCallTarget() const { return getSrc(0); } |
| 401 Operand *getArg(SizeT I) const { return getSrc(I + 1); } | 412 Operand *getArg(SizeT I) const { return getSrc(I + 1); } |
| 402 SizeT getNumArgs() const { return getSrcSize() - 1; } | 413 SizeT getNumArgs() const { return getSrcSize() - 1; } |
| 403 bool isTailcall() const { return HasTailCall; } | 414 bool isTailcall() const { return HasTailCall; } |
| 404 bool isTargetHelperCall() const { return IsTargetHelperCall; } | 415 bool isTargetHelperCall() const { return IsTargetHelperCall; } |
| 416 bool isMemoryWrite() const override { return true; } |
| 405 void dump(const Cfg *Func) const override; | 417 void dump(const Cfg *Func) const override; |
| 406 static bool classof(const Inst *Instr) { return Instr->getKind() == Call; } | 418 static bool classof(const Inst *Instr) { return Instr->getKind() == Call; } |
| 407 Type getReturnType() const; | 419 Type getReturnType() const; |
| 408 | 420 |
| 409 protected: | 421 protected: |
| 410 InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget, | 422 InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget, |
| 411 bool HasTailCall, bool IsTargetHelperCall, bool HasSideEff, | 423 bool HasTailCall, bool IsTargetHelperCall, bool HasSideEff, |
| 412 InstKind Kind) | 424 InstKind Kind) |
| 413 : InstHighLevel(Func, Kind, NumArgs + 1, Dest), HasTailCall(HasTailCall), | 425 : InstHighLevel(Func, Kind, NumArgs + 1, Dest), HasTailCall(HasTailCall), |
| 414 IsTargetHelperCall(IsTargetHelperCall) { | 426 IsTargetHelperCall(IsTargetHelperCall) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 436 }; | 448 }; |
| 437 | 449 |
| 438 static const char *getCastName(OpKind Kind); | 450 static const char *getCastName(OpKind Kind); |
| 439 | 451 |
| 440 static InstCast *create(Cfg *Func, OpKind CastKind, Variable *Dest, | 452 static InstCast *create(Cfg *Func, OpKind CastKind, Variable *Dest, |
| 441 Operand *Source) { | 453 Operand *Source) { |
| 442 return new (Func->allocate<InstCast>()) | 454 return new (Func->allocate<InstCast>()) |
| 443 InstCast(Func, CastKind, Dest, Source); | 455 InstCast(Func, CastKind, Dest, Source); |
| 444 } | 456 } |
| 445 OpKind getCastKind() const { return CastKind; } | 457 OpKind getCastKind() const { return CastKind; } |
| 458 bool isMemoryWrite() const override { return false; } |
| 446 void dump(const Cfg *Func) const override; | 459 void dump(const Cfg *Func) const override; |
| 447 static bool classof(const Inst *Instr) { return Instr->getKind() == Cast; } | 460 static bool classof(const Inst *Instr) { return Instr->getKind() == Cast; } |
| 448 | 461 |
| 449 private: | 462 private: |
| 450 InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source); | 463 InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source); |
| 451 | 464 |
| 452 const OpKind CastKind; | 465 const OpKind CastKind; |
| 453 }; | 466 }; |
| 454 | 467 |
| 455 /// ExtractElement instruction. | 468 /// ExtractElement instruction. |
| 456 class InstExtractElement : public InstHighLevel { | 469 class InstExtractElement : public InstHighLevel { |
| 457 InstExtractElement() = delete; | 470 InstExtractElement() = delete; |
| 458 InstExtractElement(const InstExtractElement &) = delete; | 471 InstExtractElement(const InstExtractElement &) = delete; |
| 459 InstExtractElement &operator=(const InstExtractElement &) = delete; | 472 InstExtractElement &operator=(const InstExtractElement &) = delete; |
| 460 | 473 |
| 461 public: | 474 public: |
| 462 static InstExtractElement *create(Cfg *Func, Variable *Dest, Operand *Source1, | 475 static InstExtractElement *create(Cfg *Func, Variable *Dest, Operand *Source1, |
| 463 Operand *Source2) { | 476 Operand *Source2) { |
| 464 return new (Func->allocate<InstExtractElement>()) | 477 return new (Func->allocate<InstExtractElement>()) |
| 465 InstExtractElement(Func, Dest, Source1, Source2); | 478 InstExtractElement(Func, Dest, Source1, Source2); |
| 466 } | 479 } |
| 467 | 480 |
| 481 bool isMemoryWrite() const override { return false; } |
| 468 void dump(const Cfg *Func) const override; | 482 void dump(const Cfg *Func) const override; |
| 469 static bool classof(const Inst *Instr) { | 483 static bool classof(const Inst *Instr) { |
| 470 return Instr->getKind() == ExtractElement; | 484 return Instr->getKind() == ExtractElement; |
| 471 } | 485 } |
| 472 | 486 |
| 473 private: | 487 private: |
| 474 InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1, | 488 InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1, |
| 475 Operand *Source2); | 489 Operand *Source2); |
| 476 }; | 490 }; |
| 477 | 491 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 489 #undef X | 503 #undef X |
| 490 _num | 504 _num |
| 491 }; | 505 }; |
| 492 | 506 |
| 493 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest, | 507 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest, |
| 494 Operand *Source1, Operand *Source2) { | 508 Operand *Source1, Operand *Source2) { |
| 495 return new (Func->allocate<InstFcmp>()) | 509 return new (Func->allocate<InstFcmp>()) |
| 496 InstFcmp(Func, Condition, Dest, Source1, Source2); | 510 InstFcmp(Func, Condition, Dest, Source1, Source2); |
| 497 } | 511 } |
| 498 FCond getCondition() const { return Condition; } | 512 FCond getCondition() const { return Condition; } |
| 513 bool isMemoryWrite() const override { return false; } |
| 499 void dump(const Cfg *Func) const override; | 514 void dump(const Cfg *Func) const override; |
| 500 static bool classof(const Inst *Instr) { return Instr->getKind() == Fcmp; } | 515 static bool classof(const Inst *Instr) { return Instr->getKind() == Fcmp; } |
| 501 | 516 |
| 502 private: | 517 private: |
| 503 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, | 518 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, |
| 504 Operand *Source2); | 519 Operand *Source2); |
| 505 | 520 |
| 506 const FCond Condition; | 521 const FCond Condition; |
| 507 }; | 522 }; |
| 508 | 523 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 520 #undef X | 535 #undef X |
| 521 _num | 536 _num |
| 522 }; | 537 }; |
| 523 | 538 |
| 524 static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest, | 539 static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest, |
| 525 Operand *Source1, Operand *Source2) { | 540 Operand *Source1, Operand *Source2) { |
| 526 return new (Func->allocate<InstIcmp>()) | 541 return new (Func->allocate<InstIcmp>()) |
| 527 InstIcmp(Func, Condition, Dest, Source1, Source2); | 542 InstIcmp(Func, Condition, Dest, Source1, Source2); |
| 528 } | 543 } |
| 529 ICond getCondition() const { return Condition; } | 544 ICond getCondition() const { return Condition; } |
| 545 bool isMemoryWrite() const override { return false; } |
| 530 void dump(const Cfg *Func) const override; | 546 void dump(const Cfg *Func) const override; |
| 531 static bool classof(const Inst *Instr) { return Instr->getKind() == Icmp; } | 547 static bool classof(const Inst *Instr) { return Instr->getKind() == Icmp; } |
| 532 | 548 |
| 533 private: | 549 private: |
| 534 InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, | 550 InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, |
| 535 Operand *Source2); | 551 Operand *Source2); |
| 536 | 552 |
| 537 const ICond Condition; | 553 const ICond Condition; |
| 538 }; | 554 }; |
| 539 | 555 |
| 540 /// InsertElement instruction. | 556 /// InsertElement instruction. |
| 541 class InstInsertElement : public InstHighLevel { | 557 class InstInsertElement : public InstHighLevel { |
| 542 InstInsertElement() = delete; | 558 InstInsertElement() = delete; |
| 543 InstInsertElement(const InstInsertElement &) = delete; | 559 InstInsertElement(const InstInsertElement &) = delete; |
| 544 InstInsertElement &operator=(const InstInsertElement &) = delete; | 560 InstInsertElement &operator=(const InstInsertElement &) = delete; |
| 545 | 561 |
| 546 public: | 562 public: |
| 547 static InstInsertElement *create(Cfg *Func, Variable *Dest, Operand *Source1, | 563 static InstInsertElement *create(Cfg *Func, Variable *Dest, Operand *Source1, |
| 548 Operand *Source2, Operand *Source3) { | 564 Operand *Source2, Operand *Source3) { |
| 549 return new (Func->allocate<InstInsertElement>()) | 565 return new (Func->allocate<InstInsertElement>()) |
| 550 InstInsertElement(Func, Dest, Source1, Source2, Source3); | 566 InstInsertElement(Func, Dest, Source1, Source2, Source3); |
| 551 } | 567 } |
| 552 | 568 |
| 569 bool isMemoryWrite() const override { return false; } |
| 553 void dump(const Cfg *Func) const override; | 570 void dump(const Cfg *Func) const override; |
| 554 static bool classof(const Inst *Instr) { | 571 static bool classof(const Inst *Instr) { |
| 555 return Instr->getKind() == InsertElement; | 572 return Instr->getKind() == InsertElement; |
| 556 } | 573 } |
| 557 | 574 |
| 558 private: | 575 private: |
| 559 InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1, | 576 InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1, |
| 560 Operand *Source2, Operand *Source3); | 577 Operand *Source2, Operand *Source3); |
| 561 }; | 578 }; |
| 562 | 579 |
| 563 /// Call to an intrinsic function. The call target is captured as getSrc(0), and | 580 /// Call to an intrinsic function. The call target is captured as getSrc(0), and |
| 564 /// arg I is captured as getSrc(I+1). | 581 /// arg I is captured as getSrc(I+1). |
| 565 class InstIntrinsicCall : public InstCall { | 582 class InstIntrinsicCall : public InstCall { |
| 566 InstIntrinsicCall() = delete; | 583 InstIntrinsicCall() = delete; |
| 567 InstIntrinsicCall(const InstIntrinsicCall &) = delete; | 584 InstIntrinsicCall(const InstIntrinsicCall &) = delete; |
| 568 InstIntrinsicCall &operator=(const InstIntrinsicCall &) = delete; | 585 InstIntrinsicCall &operator=(const InstIntrinsicCall &) = delete; |
| 569 | 586 |
| 570 public: | 587 public: |
| 571 static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, | 588 static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, |
| 572 Operand *CallTarget, | 589 Operand *CallTarget, |
| 573 const Intrinsics::IntrinsicInfo &Info) { | 590 const Intrinsics::IntrinsicInfo &Info) { |
| 574 return new (Func->allocate<InstIntrinsicCall>()) | 591 return new (Func->allocate<InstIntrinsicCall>()) |
| 575 InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info); | 592 InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info); |
| 576 } | 593 } |
| 577 static bool classof(const Inst *Instr) { | 594 static bool classof(const Inst *Instr) { |
| 578 return Instr->getKind() == IntrinsicCall; | 595 return Instr->getKind() == IntrinsicCall; |
| 579 } | 596 } |
| 580 | 597 |
| 581 Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; } | 598 Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; } |
| 599 bool isMemoryWrite() const override { |
| 600 return getIntrinsicInfo().IsMemoryWrite; |
| 601 } |
| 582 | 602 |
| 583 private: | 603 private: |
| 584 InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest, | 604 InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest, |
| 585 Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info) | 605 Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info) |
| 586 : InstCall(Func, NumArgs, Dest, CallTarget, false, false, | 606 : InstCall(Func, NumArgs, Dest, CallTarget, false, false, |
| 587 Info.HasSideEffects, Inst::IntrinsicCall), | 607 Info.HasSideEffects, Inst::IntrinsicCall), |
| 588 Info(Info) {} | 608 Info(Info) {} |
| 589 | 609 |
| 590 const Intrinsics::IntrinsicInfo Info; | 610 const Intrinsics::IntrinsicInfo Info; |
| 591 }; | 611 }; |
| 592 | 612 |
| 593 /// Load instruction. The source address is captured in getSrc(0). | 613 /// Load instruction. The source address is captured in getSrc(0). |
| 594 class InstLoad : public InstHighLevel { | 614 class InstLoad : public InstHighLevel { |
| 595 InstLoad() = delete; | 615 InstLoad() = delete; |
| 596 InstLoad(const InstLoad &) = delete; | 616 InstLoad(const InstLoad &) = delete; |
| 597 InstLoad &operator=(const InstLoad &) = delete; | 617 InstLoad &operator=(const InstLoad &) = delete; |
| 598 | 618 |
| 599 public: | 619 public: |
| 600 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr, | 620 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr, |
| 601 uint32_t Align = 1) { | 621 uint32_t Align = 1) { |
| 602 // TODO(kschimpf) Stop ignoring alignment specification. | 622 // TODO(kschimpf) Stop ignoring alignment specification. |
| 603 (void)Align; | 623 (void)Align; |
| 604 return new (Func->allocate<InstLoad>()) InstLoad(Func, Dest, SourceAddr); | 624 return new (Func->allocate<InstLoad>()) InstLoad(Func, Dest, SourceAddr); |
| 605 } | 625 } |
| 606 Operand *getSourceAddress() const { return getSrc(0); } | 626 Operand *getSourceAddress() const { return getSrc(0); } |
| 627 bool isMemoryWrite() const override { return false; } |
| 607 void dump(const Cfg *Func) const override; | 628 void dump(const Cfg *Func) const override; |
| 608 static bool classof(const Inst *Instr) { return Instr->getKind() == Load; } | 629 static bool classof(const Inst *Instr) { return Instr->getKind() == Load; } |
| 609 | 630 |
| 610 private: | 631 private: |
| 611 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr); | 632 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr); |
| 612 }; | 633 }; |
| 613 | 634 |
| 614 /// Phi instruction. For incoming edge I, the node is Labels[I] and the Phi | 635 /// Phi instruction. For incoming edge I, the node is Labels[I] and the Phi |
| 615 /// source operand is getSrc(I). | 636 /// source operand is getSrc(I). |
| 616 class InstPhi : public InstHighLevel { | 637 class InstPhi : public InstHighLevel { |
| 617 InstPhi() = delete; | 638 InstPhi() = delete; |
| 618 InstPhi(const InstPhi &) = delete; | 639 InstPhi(const InstPhi &) = delete; |
| 619 InstPhi &operator=(const InstPhi &) = delete; | 640 InstPhi &operator=(const InstPhi &) = delete; |
| 620 | 641 |
| 621 public: | 642 public: |
| 622 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) { | 643 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) { |
| 623 return new (Func->allocate<InstPhi>()) InstPhi(Func, MaxSrcs, Dest); | 644 return new (Func->allocate<InstPhi>()) InstPhi(Func, MaxSrcs, Dest); |
| 624 } | 645 } |
| 625 void addArgument(Operand *Source, CfgNode *Label); | 646 void addArgument(Operand *Source, CfgNode *Label); |
| 626 Operand *getOperandForTarget(CfgNode *Target) const; | 647 Operand *getOperandForTarget(CfgNode *Target) const; |
| 627 void clearOperandForTarget(CfgNode *Target); | 648 void clearOperandForTarget(CfgNode *Target); |
| 628 CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } | 649 CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } |
| 629 void setLabel(SizeT Index, CfgNode *Label) { Labels[Index] = Label; } | 650 void setLabel(SizeT Index, CfgNode *Label) { Labels[Index] = Label; } |
| 630 void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, | 651 void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, |
| 631 Liveness *Liveness); | 652 Liveness *Liveness); |
| 632 Inst *lower(Cfg *Func); | 653 Inst *lower(Cfg *Func); |
| 654 bool isMemoryWrite() const override { return false; } |
| 633 void dump(const Cfg *Func) const override; | 655 void dump(const Cfg *Func) const override; |
| 634 static bool classof(const Inst *Instr) { return Instr->getKind() == Phi; } | 656 static bool classof(const Inst *Instr) { return Instr->getKind() == Phi; } |
| 635 | 657 |
| 636 private: | 658 private: |
| 637 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest); | 659 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest); |
| 638 void destroy(Cfg *Func) override { | 660 void destroy(Cfg *Func) override { |
| 639 Func->deallocateArrayOf<CfgNode *>(Labels); | 661 Func->deallocateArrayOf<CfgNode *>(Labels); |
| 640 Inst::destroy(Func); | 662 Inst::destroy(Func); |
| 641 } | 663 } |
| 642 | 664 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 657 public: | 679 public: |
| 658 static InstRet *create(Cfg *Func, Operand *RetValue = nullptr) { | 680 static InstRet *create(Cfg *Func, Operand *RetValue = nullptr) { |
| 659 return new (Func->allocate<InstRet>()) InstRet(Func, RetValue); | 681 return new (Func->allocate<InstRet>()) InstRet(Func, RetValue); |
| 660 } | 682 } |
| 661 bool hasRetValue() const { return getSrcSize(); } | 683 bool hasRetValue() const { return getSrcSize(); } |
| 662 Operand *getRetValue() const { | 684 Operand *getRetValue() const { |
| 663 assert(hasRetValue()); | 685 assert(hasRetValue()); |
| 664 return getSrc(0); | 686 return getSrc(0); |
| 665 } | 687 } |
| 666 NodeList getTerminatorEdges() const override { return NodeList(); } | 688 NodeList getTerminatorEdges() const override { return NodeList(); } |
| 689 bool isMemoryWrite() const override { return false; } |
| 667 void dump(const Cfg *Func) const override; | 690 void dump(const Cfg *Func) const override; |
| 668 static bool classof(const Inst *Instr) { return Instr->getKind() == Ret; } | 691 static bool classof(const Inst *Instr) { return Instr->getKind() == Ret; } |
| 669 | 692 |
| 670 private: | 693 private: |
| 671 InstRet(Cfg *Func, Operand *RetValue); | 694 InstRet(Cfg *Func, Operand *RetValue); |
| 672 }; | 695 }; |
| 673 | 696 |
| 674 /// Select instruction. The condition, true, and false operands are captured. | 697 /// Select instruction. The condition, true, and false operands are captured. |
| 675 class InstSelect : public InstHighLevel { | 698 class InstSelect : public InstHighLevel { |
| 676 InstSelect() = delete; | 699 InstSelect() = delete; |
| 677 InstSelect(const InstSelect &) = delete; | 700 InstSelect(const InstSelect &) = delete; |
| 678 InstSelect &operator=(const InstSelect &) = delete; | 701 InstSelect &operator=(const InstSelect &) = delete; |
| 679 | 702 |
| 680 public: | 703 public: |
| 681 static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition, | 704 static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition, |
| 682 Operand *SourceTrue, Operand *SourceFalse) { | 705 Operand *SourceTrue, Operand *SourceFalse) { |
| 683 return new (Func->allocate<InstSelect>()) | 706 return new (Func->allocate<InstSelect>()) |
| 684 InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse); | 707 InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse); |
| 685 } | 708 } |
| 686 Operand *getCondition() const { return getSrc(0); } | 709 Operand *getCondition() const { return getSrc(0); } |
| 687 Operand *getTrueOperand() const { return getSrc(1); } | 710 Operand *getTrueOperand() const { return getSrc(1); } |
| 688 Operand *getFalseOperand() const { return getSrc(2); } | 711 Operand *getFalseOperand() const { return getSrc(2); } |
| 712 bool isMemoryWrite() const override { return false; } |
| 689 void dump(const Cfg *Func) const override; | 713 void dump(const Cfg *Func) const override; |
| 690 static bool classof(const Inst *Instr) { return Instr->getKind() == Select; } | 714 static bool classof(const Inst *Instr) { return Instr->getKind() == Select; } |
| 691 | 715 |
| 692 private: | 716 private: |
| 693 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1, | 717 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1, |
| 694 Operand *Source2); | 718 Operand *Source2); |
| 695 }; | 719 }; |
| 696 | 720 |
| 697 /// Store instruction. The address operand is captured, along with the data | 721 /// Store instruction. The address operand is captured, along with the data |
| 698 /// operand to be stored into the address. | 722 /// operand to be stored into the address. |
| 699 class InstStore : public InstHighLevel { | 723 class InstStore : public InstHighLevel { |
| 700 InstStore() = delete; | 724 InstStore() = delete; |
| 701 InstStore(const InstStore &) = delete; | 725 InstStore(const InstStore &) = delete; |
| 702 InstStore &operator=(const InstStore &) = delete; | 726 InstStore &operator=(const InstStore &) = delete; |
| 703 | 727 |
| 704 public: | 728 public: |
| 705 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr, | 729 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr, |
| 706 uint32_t Align = 1) { | 730 uint32_t Align = 1) { |
| 707 // TODO(kschimpf) Stop ignoring alignment specification. | 731 // TODO(kschimpf) Stop ignoring alignment specification. |
| 708 (void)Align; | 732 (void)Align; |
| 709 return new (Func->allocate<InstStore>()) InstStore(Func, Data, Addr); | 733 return new (Func->allocate<InstStore>()) InstStore(Func, Data, Addr); |
| 710 } | 734 } |
| 711 Operand *getAddr() const { return getSrc(1); } | 735 Operand *getAddr() const { return getSrc(1); } |
| 712 Operand *getData() const { return getSrc(0); } | 736 Operand *getData() const { return getSrc(0); } |
| 713 Variable *getRmwBeacon() const; | 737 Variable *getRmwBeacon() const; |
| 714 void setRmwBeacon(Variable *Beacon); | 738 void setRmwBeacon(Variable *Beacon); |
| 739 bool isMemoryWrite() const override { return true; } |
| 715 void dump(const Cfg *Func) const override; | 740 void dump(const Cfg *Func) const override; |
| 716 static bool classof(const Inst *Instr) { return Instr->getKind() == Store; } | 741 static bool classof(const Inst *Instr) { return Instr->getKind() == Store; } |
| 717 | 742 |
| 718 private: | 743 private: |
| 719 InstStore(Cfg *Func, Operand *Data, Operand *Addr); | 744 InstStore(Cfg *Func, Operand *Data, Operand *Addr); |
| 720 }; | 745 }; |
| 721 | 746 |
| 722 /// Switch instruction. The single source operand is captured as getSrc(0). | 747 /// Switch instruction. The single source operand is captured as getSrc(0). |
| 723 class InstSwitch : public InstHighLevel { | 748 class InstSwitch : public InstHighLevel { |
| 724 InstSwitch() = delete; | 749 InstSwitch() = delete; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 738 assert(I < NumCases); | 763 assert(I < NumCases); |
| 739 return Values[I]; | 764 return Values[I]; |
| 740 } | 765 } |
| 741 CfgNode *getLabel(SizeT I) const { | 766 CfgNode *getLabel(SizeT I) const { |
| 742 assert(I < NumCases); | 767 assert(I < NumCases); |
| 743 return Labels[I]; | 768 return Labels[I]; |
| 744 } | 769 } |
| 745 void addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label); | 770 void addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label); |
| 746 NodeList getTerminatorEdges() const override; | 771 NodeList getTerminatorEdges() const override; |
| 747 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; | 772 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; |
| 773 bool isMemoryWrite() const override { return false; } |
| 748 void dump(const Cfg *Func) const override; | 774 void dump(const Cfg *Func) const override; |
| 749 static bool classof(const Inst *Instr) { return Instr->getKind() == Switch; } | 775 static bool classof(const Inst *Instr) { return Instr->getKind() == Switch; } |
| 750 | 776 |
| 751 private: | 777 private: |
| 752 InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault); | 778 InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault); |
| 753 void destroy(Cfg *Func) override { | 779 void destroy(Cfg *Func) override { |
| 754 Func->deallocateArrayOf<uint64_t>(Values); | 780 Func->deallocateArrayOf<uint64_t>(Values); |
| 755 Func->deallocateArrayOf<CfgNode *>(Labels); | 781 Func->deallocateArrayOf<CfgNode *>(Labels); |
| 756 Inst::destroy(Func); | 782 Inst::destroy(Func); |
| 757 } | 783 } |
| 758 | 784 |
| 759 CfgNode *LabelDefault; | 785 CfgNode *LabelDefault; |
| 760 SizeT NumCases; /// not including the default case | 786 SizeT NumCases; /// not including the default case |
| 761 uint64_t *Values; /// size is NumCases | 787 uint64_t *Values; /// size is NumCases |
| 762 CfgNode **Labels; /// size is NumCases | 788 CfgNode **Labels; /// size is NumCases |
| 763 }; | 789 }; |
| 764 | 790 |
| 765 /// Unreachable instruction. This is a terminator instruction with no operands. | 791 /// Unreachable instruction. This is a terminator instruction with no operands. |
| 766 class InstUnreachable : public InstHighLevel { | 792 class InstUnreachable : public InstHighLevel { |
| 767 InstUnreachable() = delete; | 793 InstUnreachable() = delete; |
| 768 InstUnreachable(const InstUnreachable &) = delete; | 794 InstUnreachable(const InstUnreachable &) = delete; |
| 769 InstUnreachable &operator=(const InstUnreachable &) = delete; | 795 InstUnreachable &operator=(const InstUnreachable &) = delete; |
| 770 | 796 |
| 771 public: | 797 public: |
| 772 static InstUnreachable *create(Cfg *Func) { | 798 static InstUnreachable *create(Cfg *Func) { |
| 773 return new (Func->allocate<InstUnreachable>()) InstUnreachable(Func); | 799 return new (Func->allocate<InstUnreachable>()) InstUnreachable(Func); |
| 774 } | 800 } |
| 775 NodeList getTerminatorEdges() const override { return NodeList(); } | 801 NodeList getTerminatorEdges() const override { return NodeList(); } |
| 802 bool isMemoryWrite() const override { return false; } |
| 776 void dump(const Cfg *Func) const override; | 803 void dump(const Cfg *Func) const override; |
| 777 static bool classof(const Inst *Instr) { | 804 static bool classof(const Inst *Instr) { |
| 778 return Instr->getKind() == Unreachable; | 805 return Instr->getKind() == Unreachable; |
| 779 } | 806 } |
| 780 | 807 |
| 781 private: | 808 private: |
| 782 explicit InstUnreachable(Cfg *Func); | 809 explicit InstUnreachable(Cfg *Func); |
| 783 }; | 810 }; |
| 784 | 811 |
| 785 /// BundleLock instruction. There are no operands. Contains an option | 812 /// BundleLock instruction. There are no operands. Contains an option |
| 786 /// indicating whether align_to_end is specified. | 813 /// indicating whether align_to_end is specified. |
| 787 class InstBundleLock : public InstHighLevel { | 814 class InstBundleLock : public InstHighLevel { |
| 788 InstBundleLock() = delete; | 815 InstBundleLock() = delete; |
| 789 InstBundleLock(const InstBundleLock &) = delete; | 816 InstBundleLock(const InstBundleLock &) = delete; |
| 790 InstBundleLock &operator=(const InstBundleLock &) = delete; | 817 InstBundleLock &operator=(const InstBundleLock &) = delete; |
| 791 | 818 |
| 792 public: | 819 public: |
| 793 enum Option { Opt_None, Opt_AlignToEnd, Opt_PadToEnd }; | 820 enum Option { Opt_None, Opt_AlignToEnd, Opt_PadToEnd }; |
| 794 static InstBundleLock *create(Cfg *Func, Option BundleOption) { | 821 static InstBundleLock *create(Cfg *Func, Option BundleOption) { |
| 795 return new (Func->allocate<InstBundleLock>()) | 822 return new (Func->allocate<InstBundleLock>()) |
| 796 InstBundleLock(Func, BundleOption); | 823 InstBundleLock(Func, BundleOption); |
| 797 } | 824 } |
| 798 void emit(const Cfg *Func) const override; | 825 void emit(const Cfg *Func) const override; |
| 799 void emitIAS(const Cfg * /* Func */) const override {} | 826 void emitIAS(const Cfg * /* Func */) const override {} |
| 827 bool isMemoryWrite() const override { return false; } |
| 800 void dump(const Cfg *Func) const override; | 828 void dump(const Cfg *Func) const override; |
| 801 Option getOption() const { return BundleOption; } | 829 Option getOption() const { return BundleOption; } |
| 802 static bool classof(const Inst *Instr) { | 830 static bool classof(const Inst *Instr) { |
| 803 return Instr->getKind() == BundleLock; | 831 return Instr->getKind() == BundleLock; |
| 804 } | 832 } |
| 805 | 833 |
| 806 private: | 834 private: |
| 807 Option BundleOption; | 835 Option BundleOption; |
| 808 InstBundleLock(Cfg *Func, Option BundleOption); | 836 InstBundleLock(Cfg *Func, Option BundleOption); |
| 809 }; | 837 }; |
| 810 | 838 |
| 811 /// BundleUnlock instruction. There are no operands. | 839 /// BundleUnlock instruction. There are no operands. |
| 812 class InstBundleUnlock : public InstHighLevel { | 840 class InstBundleUnlock : public InstHighLevel { |
| 813 InstBundleUnlock() = delete; | 841 InstBundleUnlock() = delete; |
| 814 InstBundleUnlock(const InstBundleUnlock &) = delete; | 842 InstBundleUnlock(const InstBundleUnlock &) = delete; |
| 815 InstBundleUnlock &operator=(const InstBundleUnlock &) = delete; | 843 InstBundleUnlock &operator=(const InstBundleUnlock &) = delete; |
| 816 | 844 |
| 817 public: | 845 public: |
| 818 static InstBundleUnlock *create(Cfg *Func) { | 846 static InstBundleUnlock *create(Cfg *Func) { |
| 819 return new (Func->allocate<InstBundleUnlock>()) InstBundleUnlock(Func); | 847 return new (Func->allocate<InstBundleUnlock>()) InstBundleUnlock(Func); |
| 820 } | 848 } |
| 821 void emit(const Cfg *Func) const override; | 849 void emit(const Cfg *Func) const override; |
| 822 void emitIAS(const Cfg * /* Func */) const override {} | 850 void emitIAS(const Cfg * /* Func */) const override {} |
| 851 bool isMemoryWrite() const override { return false; } |
| 823 void dump(const Cfg *Func) const override; | 852 void dump(const Cfg *Func) const override; |
| 824 static bool classof(const Inst *Instr) { | 853 static bool classof(const Inst *Instr) { |
| 825 return Instr->getKind() == BundleUnlock; | 854 return Instr->getKind() == BundleUnlock; |
| 826 } | 855 } |
| 827 | 856 |
| 828 private: | 857 private: |
| 829 explicit InstBundleUnlock(Cfg *Func); | 858 explicit InstBundleUnlock(Cfg *Func); |
| 830 }; | 859 }; |
| 831 | 860 |
| 832 /// FakeDef instruction. This creates a fake definition of a variable, which is | 861 /// FakeDef instruction. This creates a fake definition of a variable, which is |
| (...skipping 12 matching lines...) Expand all Loading... |
| 845 InstFakeDef(const InstFakeDef &) = delete; | 874 InstFakeDef(const InstFakeDef &) = delete; |
| 846 InstFakeDef &operator=(const InstFakeDef &) = delete; | 875 InstFakeDef &operator=(const InstFakeDef &) = delete; |
| 847 | 876 |
| 848 public: | 877 public: |
| 849 static InstFakeDef *create(Cfg *Func, Variable *Dest, | 878 static InstFakeDef *create(Cfg *Func, Variable *Dest, |
| 850 Variable *Src = nullptr) { | 879 Variable *Src = nullptr) { |
| 851 return new (Func->allocate<InstFakeDef>()) InstFakeDef(Func, Dest, Src); | 880 return new (Func->allocate<InstFakeDef>()) InstFakeDef(Func, Dest, Src); |
| 852 } | 881 } |
| 853 void emit(const Cfg *Func) const override; | 882 void emit(const Cfg *Func) const override; |
| 854 void emitIAS(const Cfg * /* Func */) const override {} | 883 void emitIAS(const Cfg * /* Func */) const override {} |
| 884 bool isMemoryWrite() const override { return false; } |
| 855 void dump(const Cfg *Func) const override; | 885 void dump(const Cfg *Func) const override; |
| 856 static bool classof(const Inst *Instr) { return Instr->getKind() == FakeDef; } | 886 static bool classof(const Inst *Instr) { return Instr->getKind() == FakeDef; } |
| 857 | 887 |
| 858 private: | 888 private: |
| 859 InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src); | 889 InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src); |
| 860 }; | 890 }; |
| 861 | 891 |
| 862 /// FakeUse instruction. This creates a fake use of a variable, to keep the | 892 /// FakeUse instruction. This creates a fake use of a variable, to keep the |
| 863 /// instruction that produces that variable from being dead-code eliminated. | 893 /// instruction that produces that variable from being dead-code eliminated. |
| 864 /// This is useful in a variety of lowering situations. The FakeUse instruction | 894 /// This is useful in a variety of lowering situations. The FakeUse instruction |
| 865 /// has no dest, so it can itself never be dead-code eliminated. A weight can | 895 /// has no dest, so it can itself never be dead-code eliminated. A weight can |
| 866 /// be provided to provide extra bias to the register allocator - for simplicity | 896 /// be provided to provide extra bias to the register allocator - for simplicity |
| 867 /// of implementation, weight=N is handled by holding N copies of the variable | 897 /// of implementation, weight=N is handled by holding N copies of the variable |
| 868 /// as source operands. | 898 /// as source operands. |
| 869 class InstFakeUse : public InstHighLevel { | 899 class InstFakeUse : public InstHighLevel { |
| 870 InstFakeUse() = delete; | 900 InstFakeUse() = delete; |
| 871 InstFakeUse(const InstFakeUse &) = delete; | 901 InstFakeUse(const InstFakeUse &) = delete; |
| 872 InstFakeUse &operator=(const InstFakeUse &) = delete; | 902 InstFakeUse &operator=(const InstFakeUse &) = delete; |
| 873 | 903 |
| 874 public: | 904 public: |
| 875 static InstFakeUse *create(Cfg *Func, Variable *Src, uint32_t Weight = 1) { | 905 static InstFakeUse *create(Cfg *Func, Variable *Src, uint32_t Weight = 1) { |
| 876 return new (Func->allocate<InstFakeUse>()) InstFakeUse(Func, Src, Weight); | 906 return new (Func->allocate<InstFakeUse>()) InstFakeUse(Func, Src, Weight); |
| 877 } | 907 } |
| 878 void emit(const Cfg *Func) const override; | 908 void emit(const Cfg *Func) const override; |
| 879 void emitIAS(const Cfg * /* Func */) const override {} | 909 void emitIAS(const Cfg * /* Func */) const override {} |
| 910 bool isMemoryWrite() const override { return false; } |
| 880 void dump(const Cfg *Func) const override; | 911 void dump(const Cfg *Func) const override; |
| 881 static bool classof(const Inst *Instr) { return Instr->getKind() == FakeUse; } | 912 static bool classof(const Inst *Instr) { return Instr->getKind() == FakeUse; } |
| 882 | 913 |
| 883 private: | 914 private: |
| 884 InstFakeUse(Cfg *Func, Variable *Src, uint32_t Weight); | 915 InstFakeUse(Cfg *Func, Variable *Src, uint32_t Weight); |
| 885 }; | 916 }; |
| 886 | 917 |
| 887 /// FakeKill instruction. This "kills" a set of variables by modeling a trivial | 918 /// FakeKill instruction. This "kills" a set of variables by modeling a trivial |
| 888 /// live range at this instruction for each (implicit) variable. The primary use | 919 /// live range at this instruction for each (implicit) variable. The primary use |
| 889 /// is to indicate that scratch registers are killed after a call, so that the | 920 /// is to indicate that scratch registers are killed after a call, so that the |
| 890 /// register allocator won't assign a scratch register to a variable whose live | 921 /// register allocator won't assign a scratch register to a variable whose live |
| 891 /// range spans a call. | 922 /// range spans a call. |
| 892 /// | 923 /// |
| 893 /// The FakeKill instruction also holds a pointer to the instruction that kills | 924 /// The FakeKill instruction also holds a pointer to the instruction that kills |
| 894 /// the set of variables, so that if that linked instruction gets dead-code | 925 /// the set of variables, so that if that linked instruction gets dead-code |
| 895 /// eliminated, the FakeKill instruction will as well. | 926 /// eliminated, the FakeKill instruction will as well. |
| 896 class InstFakeKill : public InstHighLevel { | 927 class InstFakeKill : public InstHighLevel { |
| 897 InstFakeKill() = delete; | 928 InstFakeKill() = delete; |
| 898 InstFakeKill(const InstFakeKill &) = delete; | 929 InstFakeKill(const InstFakeKill &) = delete; |
| 899 InstFakeKill &operator=(const InstFakeKill &) = delete; | 930 InstFakeKill &operator=(const InstFakeKill &) = delete; |
| 900 | 931 |
| 901 public: | 932 public: |
| 902 static InstFakeKill *create(Cfg *Func, const Inst *Linked) { | 933 static InstFakeKill *create(Cfg *Func, const Inst *Linked) { |
| 903 return new (Func->allocate<InstFakeKill>()) InstFakeKill(Func, Linked); | 934 return new (Func->allocate<InstFakeKill>()) InstFakeKill(Func, Linked); |
| 904 } | 935 } |
| 905 const Inst *getLinked() const { return Linked; } | 936 const Inst *getLinked() const { return Linked; } |
| 906 void emit(const Cfg *Func) const override; | 937 void emit(const Cfg *Func) const override; |
| 907 void emitIAS(const Cfg * /* Func */) const override {} | 938 void emitIAS(const Cfg * /* Func */) const override {} |
| 939 bool isMemoryWrite() const override { return false; } |
| 908 void dump(const Cfg *Func) const override; | 940 void dump(const Cfg *Func) const override; |
| 909 static bool classof(const Inst *Instr) { | 941 static bool classof(const Inst *Instr) { |
| 910 return Instr->getKind() == FakeKill; | 942 return Instr->getKind() == FakeKill; |
| 911 } | 943 } |
| 912 | 944 |
| 913 private: | 945 private: |
| 914 InstFakeKill(Cfg *Func, const Inst *Linked); | 946 InstFakeKill(Cfg *Func, const Inst *Linked); |
| 915 | 947 |
| 916 /// This instruction is ignored if Linked->isDeleted() is true. | 948 /// This instruction is ignored if Linked->isDeleted() is true. |
| 917 const Inst *Linked; | 949 const Inst *Linked; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 934 assert(TargetIndex < NumTargets); | 966 assert(TargetIndex < NumTargets); |
| 935 Targets[TargetIndex] = Target; | 967 Targets[TargetIndex] = Target; |
| 936 } | 968 } |
| 937 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; | 969 bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; |
| 938 SizeT getId() const { return Id; } | 970 SizeT getId() const { return Id; } |
| 939 SizeT getNumTargets() const { return NumTargets; } | 971 SizeT getNumTargets() const { return NumTargets; } |
| 940 CfgNode *getTarget(SizeT I) const { | 972 CfgNode *getTarget(SizeT I) const { |
| 941 assert(I < NumTargets); | 973 assert(I < NumTargets); |
| 942 return Targets[I]; | 974 return Targets[I]; |
| 943 } | 975 } |
| 976 bool isMemoryWrite() const override { return false; } |
| 944 void dump(const Cfg *Func) const override; | 977 void dump(const Cfg *Func) const override; |
| 945 static bool classof(const Inst *Instr) { | 978 static bool classof(const Inst *Instr) { |
| 946 return Instr->getKind() == JumpTable; | 979 return Instr->getKind() == JumpTable; |
| 947 } | 980 } |
| 948 // Creates a JumpTableData struct (used for ELF emission) that represents this | 981 // Creates a JumpTableData struct (used for ELF emission) that represents this |
| 949 // InstJumpTable. | 982 // InstJumpTable. |
| 950 JumpTableData toJumpTableData(Assembler *Asm) const; | 983 JumpTableData toJumpTableData(Assembler *Asm) const; |
| 951 | 984 |
| 952 // InstJumpTable is just a placeholder for the switch targets, and it does not | 985 // InstJumpTable is just a placeholder for the switch targets, and it does not |
| 953 // need to emit any code, so we redefine emit and emitIAS to do nothing. | 986 // need to emit any code, so we redefine emit and emitIAS to do nothing. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 981 /// | 1014 /// |
| 982 /// On x86, this assembles into an INT 3 instruction. | 1015 /// On x86, this assembles into an INT 3 instruction. |
| 983 /// | 1016 /// |
| 984 /// This instruction is primarily meant for debugging the code generator. | 1017 /// This instruction is primarily meant for debugging the code generator. |
| 985 class InstBreakpoint : public InstHighLevel { | 1018 class InstBreakpoint : public InstHighLevel { |
| 986 public: | 1019 public: |
| 987 InstBreakpoint() = delete; | 1020 InstBreakpoint() = delete; |
| 988 InstBreakpoint(const InstBreakpoint &) = delete; | 1021 InstBreakpoint(const InstBreakpoint &) = delete; |
| 989 InstBreakpoint &operator=(const InstBreakpoint &) = delete; | 1022 InstBreakpoint &operator=(const InstBreakpoint &) = delete; |
| 990 | 1023 |
| 991 InstBreakpoint(Cfg *Func); | 1024 explicit InstBreakpoint(Cfg *Func); |
| 1025 bool isMemoryWrite() const override { return false; } |
| 992 | 1026 |
| 993 public: | 1027 public: |
| 994 static InstBreakpoint *create(Cfg *Func) { | 1028 static InstBreakpoint *create(Cfg *Func) { |
| 995 return new (Func->allocate<InstBreakpoint>()) InstBreakpoint(Func); | 1029 return new (Func->allocate<InstBreakpoint>()) InstBreakpoint(Func); |
| 996 } | 1030 } |
| 997 | 1031 |
| 998 static bool classof(const Inst *Instr) { | 1032 static bool classof(const Inst *Instr) { |
| 999 return Instr->getKind() == Breakpoint; | 1033 return Instr->getKind() == Breakpoint; |
| 1000 } | 1034 } |
| 1001 }; | 1035 }; |
| 1002 | 1036 |
| 1003 /// The Target instruction is the base class for all target-specific | 1037 /// The Target instruction is the base class for all target-specific |
| 1004 /// instructions. | 1038 /// instructions. |
| 1005 class InstTarget : public Inst { | 1039 class InstTarget : public Inst { |
| 1006 InstTarget() = delete; | 1040 InstTarget() = delete; |
| 1007 InstTarget(const InstTarget &) = delete; | 1041 InstTarget(const InstTarget &) = delete; |
| 1008 InstTarget &operator=(const InstTarget &) = delete; | 1042 InstTarget &operator=(const InstTarget &) = delete; |
| 1009 | 1043 |
| 1010 public: | 1044 public: |
| 1011 uint32_t getEmitInstCount() const override { return 1; } | 1045 uint32_t getEmitInstCount() const override { return 1; } |
| 1046 bool isMemoryWrite() const override { |
| 1047 return true; // conservative answer |
| 1048 } |
| 1012 void dump(const Cfg *Func) const override; | 1049 void dump(const Cfg *Func) const override; |
| 1013 static bool classof(const Inst *Instr) { return Instr->getKind() >= Target; } | 1050 static bool classof(const Inst *Instr) { return Instr->getKind() >= Target; } |
| 1014 | 1051 |
| 1015 protected: | 1052 protected: |
| 1016 InstTarget(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) | 1053 InstTarget(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| 1017 : Inst(Func, Kind, MaxSrcs, Dest) { | 1054 : Inst(Func, Kind, MaxSrcs, Dest) { |
| 1018 assert(Kind >= Target); | 1055 assert(Kind >= Target); |
| 1019 assert(Kind <= Target_Max); | 1056 assert(Kind <= Target_Max); |
| 1020 } | 1057 } |
| 1021 }; | 1058 }; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1039 static void noteHead(Ice::Inst *, Ice::Inst *) {} | 1076 static void noteHead(Ice::Inst *, Ice::Inst *) {} |
| 1040 void deleteNode(Ice::Inst *) {} | 1077 void deleteNode(Ice::Inst *) {} |
| 1041 | 1078 |
| 1042 private: | 1079 private: |
| 1043 mutable ilist_half_node<Ice::Inst> Sentinel; | 1080 mutable ilist_half_node<Ice::Inst> Sentinel; |
| 1044 }; | 1081 }; |
| 1045 | 1082 |
| 1046 } // end of namespace llvm | 1083 } // end of namespace llvm |
| 1047 | 1084 |
| 1048 #endif // SUBZERO_SRC_ICEINST_H | 1085 #endif // SUBZERO_SRC_ICEINST_H |
| OLD | NEW |