| OLD | NEW |
| 1 //===- subzero/src/IceInst.cpp - High-level instruction implementation ----===// | 1 //===- subzero/src/IceInst.cpp - High-level instruction implementation ----===// |
| 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 |
| 11 /// This file implements the Inst class, primarily the various | 11 /// This file implements the Inst class, primarily the various |
| 12 /// subclass constructors and dump routines. | 12 /// subclass constructors and dump routines. |
| 13 /// | 13 /// |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #include "IceInst.h" | 16 #include "IceInst.h" |
| 17 | 17 |
| 18 #include "IceCfg.h" | 18 #include "IceCfg.h" |
| 19 #include "IceCfgNode.h" | 19 #include "IceCfgNode.h" |
| 20 #include "IceLiveness.h" | 20 #include "IceLiveness.h" |
| 21 #include "IceOperand.h" | 21 #include "IceOperand.h" |
| 22 #include "IceTargetLowering.h" |
| 22 | 23 |
| 23 namespace Ice { | 24 namespace Ice { |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 27 // Using non-anonymous struct so that array_lengthof works. | 28 // Using non-anonymous struct so that array_lengthof works. |
| 28 const struct InstArithmeticAttributes_ { | 29 const struct InstArithmeticAttributes_ { |
| 29 const char *DisplayString; | 30 const char *DisplayString; |
| 30 bool IsCommutative; | 31 bool IsCommutative; |
| 31 } InstArithmeticAttributes[] = { | 32 } InstArithmeticAttributes[] = { |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 | 289 |
| 289 NodeList InstBr::getTerminatorEdges() const { | 290 NodeList InstBr::getTerminatorEdges() const { |
| 290 NodeList OutEdges; | 291 NodeList OutEdges; |
| 291 OutEdges.reserve(TargetTrue ? 2 : 1); | 292 OutEdges.reserve(TargetTrue ? 2 : 1); |
| 292 OutEdges.push_back(TargetFalse); | 293 OutEdges.push_back(TargetFalse); |
| 293 if (TargetTrue) | 294 if (TargetTrue) |
| 294 OutEdges.push_back(TargetTrue); | 295 OutEdges.push_back(TargetTrue); |
| 295 return OutEdges; | 296 return OutEdges; |
| 296 } | 297 } |
| 297 | 298 |
| 298 bool InstBr::repointEdge(CfgNode *OldNode, CfgNode *NewNode) { | 299 bool InstBr::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
| 300 bool Found = false; |
| 299 if (TargetFalse == OldNode) { | 301 if (TargetFalse == OldNode) { |
| 300 TargetFalse = NewNode; | 302 TargetFalse = NewNode; |
| 301 return true; | 303 Found = true; |
| 302 } else if (TargetTrue == OldNode) { | 304 } |
| 305 if (TargetTrue == OldNode) { |
| 303 TargetTrue = NewNode; | 306 TargetTrue = NewNode; |
| 304 return true; | 307 Found = true; |
| 305 } | 308 } |
| 306 return false; | 309 return Found; |
| 307 } | 310 } |
| 308 | 311 |
| 309 InstCast::InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source) | 312 InstCast::InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source) |
| 310 : InstHighLevel(Func, Inst::Cast, 1, Dest), CastKind(CastKind) { | 313 : InstHighLevel(Func, Inst::Cast, 1, Dest), CastKind(CastKind) { |
| 311 addSource(Source); | 314 addSource(Source); |
| 312 } | 315 } |
| 313 | 316 |
| 314 InstExtractElement::InstExtractElement(Cfg *Func, Variable *Dest, | 317 InstExtractElement::InstExtractElement(Cfg *Func, Variable *Dest, |
| 315 Operand *Source1, Operand *Source2) | 318 Operand *Source1, Operand *Source2) |
| 316 : InstHighLevel(Func, Inst::ExtractElement, 2, Dest) { | 319 : InstHighLevel(Func, Inst::ExtractElement, 2, Dest) { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 Labels[CaseIndex] = Label; | 457 Labels[CaseIndex] = Label; |
| 455 } | 458 } |
| 456 | 459 |
| 457 NodeList InstSwitch::getTerminatorEdges() const { | 460 NodeList InstSwitch::getTerminatorEdges() const { |
| 458 NodeList OutEdges; | 461 NodeList OutEdges; |
| 459 OutEdges.reserve(NumCases + 1); | 462 OutEdges.reserve(NumCases + 1); |
| 460 OutEdges.push_back(LabelDefault); | 463 OutEdges.push_back(LabelDefault); |
| 461 for (SizeT I = 0; I < NumCases; ++I) { | 464 for (SizeT I = 0; I < NumCases; ++I) { |
| 462 OutEdges.push_back(Labels[I]); | 465 OutEdges.push_back(Labels[I]); |
| 463 } | 466 } |
| 467 std::sort(OutEdges.begin(), OutEdges.end(), |
| 468 [](const CfgNode *x, const CfgNode *y) { |
| 469 return x->getIndex() < y->getIndex(); |
| 470 }); |
| 471 auto Last = std::unique(OutEdges.begin(), OutEdges.end()); |
| 472 OutEdges.erase(Last, OutEdges.end()); |
| 464 return OutEdges; | 473 return OutEdges; |
| 465 } | 474 } |
| 466 | 475 |
| 467 bool InstSwitch::repointEdge(CfgNode *OldNode, CfgNode *NewNode) { | 476 bool InstSwitch::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
| 477 bool Found = false; |
| 468 if (LabelDefault == OldNode) { | 478 if (LabelDefault == OldNode) { |
| 469 LabelDefault = NewNode; | 479 LabelDefault = NewNode; |
| 470 return true; | 480 Found = true; |
| 471 } | 481 } |
| 472 for (SizeT I = 0; I < NumCases; ++I) { | 482 for (SizeT I = 0; I < NumCases; ++I) { |
| 473 if (Labels[I] == OldNode) { | 483 if (Labels[I] == OldNode) { |
| 474 Labels[I] = NewNode; | 484 Labels[I] = NewNode; |
| 475 return true; | 485 Found = true; |
| 476 } | 486 } |
| 477 } | 487 } |
| 478 return false; | 488 return Found; |
| 479 } | 489 } |
| 480 | 490 |
| 481 InstUnreachable::InstUnreachable(Cfg *Func) | 491 InstUnreachable::InstUnreachable(Cfg *Func) |
| 482 : InstHighLevel(Func, Inst::Unreachable, 0, nullptr) {} | 492 : InstHighLevel(Func, Inst::Unreachable, 0, nullptr) {} |
| 483 | 493 |
| 484 InstBundleLock::InstBundleLock(Cfg *Func, InstBundleLock::Option BundleOption) | 494 InstBundleLock::InstBundleLock(Cfg *Func, InstBundleLock::Option BundleOption) |
| 485 : InstHighLevel(Func, Inst::BundleLock, 0, nullptr), | 495 : InstHighLevel(Func, Inst::BundleLock, 0, nullptr), |
| 486 BundleOption(BundleOption) {} | 496 BundleOption(BundleOption) {} |
| 487 | 497 |
| 488 InstBundleUnlock::InstBundleUnlock(Cfg *Func) | 498 InstBundleUnlock::InstBundleUnlock(Cfg *Func) |
| 489 : InstHighLevel(Func, Inst::BundleUnlock, 0, nullptr) {} | 499 : InstHighLevel(Func, Inst::BundleUnlock, 0, nullptr) {} |
| 490 | 500 |
| 491 InstFakeDef::InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src) | 501 InstFakeDef::InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src) |
| 492 : InstHighLevel(Func, Inst::FakeDef, Src ? 1 : 0, Dest) { | 502 : InstHighLevel(Func, Inst::FakeDef, Src ? 1 : 0, Dest) { |
| 493 assert(Dest); | 503 assert(Dest); |
| 494 if (Src) | 504 if (Src) |
| 495 addSource(Src); | 505 addSource(Src); |
| 496 } | 506 } |
| 497 | 507 |
| 498 InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src) | 508 InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src) |
| 499 : InstHighLevel(Func, Inst::FakeUse, 1, nullptr) { | 509 : InstHighLevel(Func, Inst::FakeUse, 1, nullptr) { |
| 500 assert(Src); | 510 assert(Src); |
| 501 addSource(Src); | 511 addSource(Src); |
| 502 } | 512 } |
| 503 | 513 |
| 504 InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked) | 514 InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked) |
| 505 : InstHighLevel(Func, Inst::FakeKill, 0, nullptr), Linked(Linked) {} | 515 : InstHighLevel(Func, Inst::FakeKill, 0, nullptr), Linked(Linked) {} |
| 506 | 516 |
| 517 InstJumpTable::InstJumpTable(Cfg *Func, SizeT NumTargets, CfgNode *Default) |
| 518 : InstHighLevel(Func, Inst::JumpTable, 1, nullptr), |
| 519 LabelNumber(Func->getTarget()->makeNextLabelNumber()), |
| 520 NumTargets(NumTargets) { |
| 521 Targets = Func->allocateArrayOf<CfgNode *>(NumTargets); |
| 522 for (SizeT I = 0; I < NumTargets; ++I) |
| 523 Targets[I] = Default; |
| 524 } |
| 525 |
| 526 bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
| 527 bool Found = false; |
| 528 for (SizeT I = 0; I < NumTargets; ++I) { |
| 529 if (Targets[I] == OldNode) { |
| 530 Targets[I] = NewNode; |
| 531 Found = true; |
| 532 } |
| 533 } |
| 534 return Found; |
| 535 } |
| 536 |
| 537 IceString InstJumpTable::getName(const Cfg *Func) const { |
| 538 return ".L" + Func->getFunctionName() + "$jumptable$__" + |
| 539 std::to_string(LabelNumber); |
| 540 } |
| 541 |
| 507 Type InstCall::getReturnType() const { | 542 Type InstCall::getReturnType() const { |
| 508 if (Dest == nullptr) | 543 if (Dest == nullptr) |
| 509 return IceType_void; | 544 return IceType_void; |
| 510 return Dest->getType(); | 545 return Dest->getType(); |
| 511 } | 546 } |
| 512 | 547 |
| 513 // ======================== Dump routines ======================== // | 548 // ======================== Dump routines ======================== // |
| 514 | 549 |
| 515 void Inst::dumpDecorated(const Cfg *Func) const { | 550 void Inst::dumpDecorated(const Cfg *Func) const { |
| 516 if (!BuildDefs::dump()) | 551 if (!BuildDefs::dump()) |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 | 945 |
| 911 void InstFakeKill::dump(const Cfg *Func) const { | 946 void InstFakeKill::dump(const Cfg *Func) const { |
| 912 if (!BuildDefs::dump()) | 947 if (!BuildDefs::dump()) |
| 913 return; | 948 return; |
| 914 Ostream &Str = Func->getContext()->getStrDump(); | 949 Ostream &Str = Func->getContext()->getStrDump(); |
| 915 if (Linked->isDeleted()) | 950 if (Linked->isDeleted()) |
| 916 Str << "// "; | 951 Str << "// "; |
| 917 Str << "kill.pseudo scratch_regs"; | 952 Str << "kill.pseudo scratch_regs"; |
| 918 } | 953 } |
| 919 | 954 |
| 955 void InstJumpTable::emit(const Cfg *Func) const { |
| 956 // TODO(ascull): should this be a target specific lowering (with access built |
| 957 // in?) and just have InstJumpTable as a high level, similar to br? or should |
| 958 // this follow the same path as emitIAS i.e. put it in global context and |
| 959 // produce this code later? |
| 960 if (!BuildDefs::dump()) |
| 961 return; |
| 962 Ostream &Str = Func->getContext()->getStrEmit(); |
| 963 // TODO(ascull): softcode pointer size of 4 |
| 964 // TODO(ascull): is .long portable? |
| 965 Str << "\n\t.section\t.rodata." << Func->getFunctionName() |
| 966 << "$jumptable,\"a\",@progbits\n" |
| 967 << "\t.align 4\n" << getName(Func) << ":"; |
| 968 for (SizeT I = 0; I < NumTargets; ++I) |
| 969 Str << "\n\t.long\t" << Targets[I]->getAsmName(); |
| 970 Str << "\n\n\t.text"; |
| 971 } |
| 972 |
| 973 void InstJumpTable::emitIAS(const Cfg *Func) const { |
| 974 // TODO(ascull): put jump table in the global context for emission later |
| 975 (void)Func; |
| 976 } |
| 977 |
| 978 void InstJumpTable::dump(const Cfg *Func) const { |
| 979 if (!BuildDefs::dump()) |
| 980 return; |
| 981 Ostream &Str = Func->getContext()->getStrDump(); |
| 982 Str << "jump table ["; |
| 983 for (SizeT I = 0; I < NumTargets; ++I) |
| 984 Str << "\n " << Targets[I]->getName(); |
| 985 Str << "\n ]"; |
| 986 } |
| 987 |
| 920 void InstTarget::dump(const Cfg *Func) const { | 988 void InstTarget::dump(const Cfg *Func) const { |
| 921 if (!BuildDefs::dump()) | 989 if (!BuildDefs::dump()) |
| 922 return; | 990 return; |
| 923 Ostream &Str = Func->getContext()->getStrDump(); | 991 Ostream &Str = Func->getContext()->getStrDump(); |
| 924 Str << "[TARGET] "; | 992 Str << "[TARGET] "; |
| 925 Inst::dump(Func); | 993 Inst::dump(Func); |
| 926 } | 994 } |
| 927 | 995 |
| 928 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) { | 996 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) { |
| 929 const auto SrcVar = llvm::dyn_cast<const Variable>(Source); | 997 const auto SrcVar = llvm::dyn_cast<const Variable>(Source); |
| 930 if (!SrcVar) | 998 if (!SrcVar) |
| 931 return false; | 999 return false; |
| 932 if (Dest->hasReg() && Dest->getRegNum() == SrcVar->getRegNum()) { | 1000 if (Dest->hasReg() && Dest->getRegNum() == SrcVar->getRegNum()) { |
| 933 // TODO: On x86-64, instructions like "mov eax, eax" are used to | 1001 // TODO: On x86-64, instructions like "mov eax, eax" are used to |
| 934 // clear the upper 32 bits of rax. We need to recognize and | 1002 // clear the upper 32 bits of rax. We need to recognize and |
| 935 // preserve these. | 1003 // preserve these. |
| 936 return true; | 1004 return true; |
| 937 } | 1005 } |
| 938 if (!Dest->hasReg() && !SrcVar->hasReg() && | 1006 if (!Dest->hasReg() && !SrcVar->hasReg() && |
| 939 Dest->getStackOffset() == SrcVar->getStackOffset()) | 1007 Dest->getStackOffset() == SrcVar->getStackOffset()) |
| 940 return true; | 1008 return true; |
| 941 return false; | 1009 return false; |
| 942 } | 1010 } |
| 943 | 1011 |
| 944 } // end of namespace Ice | 1012 } // end of namespace Ice |
| OLD | NEW |