Chromium Code Reviews| 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()); | |
|
Jim Stichnoth
2015/07/15 19:17:42
What is the comparison function here? It needs to
ascull
2015/07/16 19:38:45
Done.
| |
| 468 auto last = std::unique(OutEdges.begin(), OutEdges.end()); | |
|
Jim Stichnoth
2015/07/15 19:17:42
capitalize Last per LLVM convention
ascull
2015/07/16 19:38:45
Done.
| |
| 469 OutEdges.erase(last, OutEdges.end()); | |
| 464 return OutEdges; | 470 return OutEdges; |
| 465 } | 471 } |
| 466 | 472 |
| 467 bool InstSwitch::repointEdge(CfgNode *OldNode, CfgNode *NewNode) { | 473 bool InstSwitch::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
| 474 bool Found = false; | |
| 468 if (LabelDefault == OldNode) { | 475 if (LabelDefault == OldNode) { |
| 469 LabelDefault = NewNode; | 476 LabelDefault = NewNode; |
| 470 return true; | 477 Found = true; |
| 471 } | 478 } |
| 472 for (SizeT I = 0; I < NumCases; ++I) { | 479 for (SizeT I = 0; I < NumCases; ++I) { |
| 473 if (Labels[I] == OldNode) { | 480 if (Labels[I] == OldNode) { |
| 474 Labels[I] = NewNode; | 481 Labels[I] = NewNode; |
| 475 return true; | 482 Found = true; |
| 476 } | 483 } |
| 477 } | 484 } |
| 478 return false; | 485 return Found; |
| 479 } | 486 } |
| 480 | 487 |
| 481 InstUnreachable::InstUnreachable(Cfg *Func) | 488 InstUnreachable::InstUnreachable(Cfg *Func) |
| 482 : InstHighLevel(Func, Inst::Unreachable, 0, nullptr) {} | 489 : InstHighLevel(Func, Inst::Unreachable, 0, nullptr) {} |
| 483 | 490 |
| 484 InstBundleLock::InstBundleLock(Cfg *Func, InstBundleLock::Option BundleOption) | 491 InstBundleLock::InstBundleLock(Cfg *Func, InstBundleLock::Option BundleOption) |
| 485 : InstHighLevel(Func, Inst::BundleLock, 0, nullptr), | 492 : InstHighLevel(Func, Inst::BundleLock, 0, nullptr), |
| 486 BundleOption(BundleOption) {} | 493 BundleOption(BundleOption) {} |
| 487 | 494 |
| 488 InstBundleUnlock::InstBundleUnlock(Cfg *Func) | 495 InstBundleUnlock::InstBundleUnlock(Cfg *Func) |
| 489 : InstHighLevel(Func, Inst::BundleUnlock, 0, nullptr) {} | 496 : InstHighLevel(Func, Inst::BundleUnlock, 0, nullptr) {} |
| 490 | 497 |
| 491 InstFakeDef::InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src) | 498 InstFakeDef::InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src) |
| 492 : InstHighLevel(Func, Inst::FakeDef, Src ? 1 : 0, Dest) { | 499 : InstHighLevel(Func, Inst::FakeDef, Src ? 1 : 0, Dest) { |
| 493 assert(Dest); | 500 assert(Dest); |
| 494 if (Src) | 501 if (Src) |
| 495 addSource(Src); | 502 addSource(Src); |
| 496 } | 503 } |
| 497 | 504 |
| 498 InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src) | 505 InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src) |
| 499 : InstHighLevel(Func, Inst::FakeUse, 1, nullptr) { | 506 : InstHighLevel(Func, Inst::FakeUse, 1, nullptr) { |
| 500 assert(Src); | 507 assert(Src); |
| 501 addSource(Src); | 508 addSource(Src); |
| 502 } | 509 } |
| 503 | 510 |
| 504 InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked) | 511 InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked) |
| 505 : InstHighLevel(Func, Inst::FakeKill, 0, nullptr), Linked(Linked) {} | 512 : InstHighLevel(Func, Inst::FakeKill, 0, nullptr), Linked(Linked) {} |
| 506 | 513 |
| 514 InstJumpTable::InstJumpTable(Cfg *Func, SizeT NumTargets, CfgNode *Default) | |
| 515 : InstHighLevel(Func, Inst::JumpTable, 1, nullptr), | |
| 516 Number(Func->getTarget()->makeNextLabelNumber()), NumTargets(NumTargets) { | |
| 517 Targets = Func->allocateArrayOf<CfgNode *>(NumTargets); | |
| 518 for (SizeT I = 0; I < NumTargets; ++I) | |
| 519 Targets[I] = Default; | |
|
Jim Stichnoth
2015/07/15 19:17:42
For safety, maybe all of these could be initialize
ascull
2015/07/16 19:38:45
Every element of the jump table can be jumped to s
| |
| 520 } | |
| 521 | |
| 522 bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { | |
| 523 bool Found = false; | |
| 524 for (SizeT I = 0; I < NumTargets; ++I) { | |
| 525 if (Targets[I] == OldNode) { | |
| 526 Targets[I] = NewNode; | |
| 527 Found = true; | |
| 528 } | |
| 529 } | |
| 530 return Found; | |
| 531 } | |
| 532 | |
| 533 IceString InstJumpTable::getName(const Cfg *Func) const { | |
| 534 return ".L" + Func->getFunctionName() | |
| 535 + "$jumptable$__" + std::to_string(Number); | |
| 536 } | |
| 537 | |
| 507 Type InstCall::getReturnType() const { | 538 Type InstCall::getReturnType() const { |
| 508 if (Dest == nullptr) | 539 if (Dest == nullptr) |
| 509 return IceType_void; | 540 return IceType_void; |
| 510 return Dest->getType(); | 541 return Dest->getType(); |
| 511 } | 542 } |
| 512 | 543 |
| 513 // ======================== Dump routines ======================== // | 544 // ======================== Dump routines ======================== // |
| 514 | 545 |
| 515 void Inst::dumpDecorated(const Cfg *Func) const { | 546 void Inst::dumpDecorated(const Cfg *Func) const { |
| 516 if (!BuildDefs::dump()) | 547 if (!BuildDefs::dump()) |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 910 | 941 |
| 911 void InstFakeKill::dump(const Cfg *Func) const { | 942 void InstFakeKill::dump(const Cfg *Func) const { |
| 912 if (!BuildDefs::dump()) | 943 if (!BuildDefs::dump()) |
| 913 return; | 944 return; |
| 914 Ostream &Str = Func->getContext()->getStrDump(); | 945 Ostream &Str = Func->getContext()->getStrDump(); |
| 915 if (Linked->isDeleted()) | 946 if (Linked->isDeleted()) |
| 916 Str << "// "; | 947 Str << "// "; |
| 917 Str << "kill.pseudo scratch_regs"; | 948 Str << "kill.pseudo scratch_regs"; |
| 918 } | 949 } |
| 919 | 950 |
| 951 void InstJumpTable::emit(const Cfg *Func) const { | |
|
Jim Stichnoth
2015/07/15 19:17:42
This should be tied in to the target data lowering
ascull
2015/07/16 19:38:45
I'm going to be doing this for emitIAS which is st
Jim Stichnoth
2015/07/17 15:33:47
TODO is fine for now, thanks.
| |
| 952 // TODO(ascull): should this be a target specific lowering (with access built | |
| 953 // in?) and just have InstJumpTable as a high level, similar to br? or should | |
| 954 // this follow the same path as emitIAS i.e. put it in global context and | |
| 955 // produce this code later? | |
| 956 if (!BuildDefs::dump()) | |
| 957 return; | |
| 958 Ostream &Str = Func->getContext()->getStrEmit(); | |
| 959 // TODO(ascull): softcode pointer size of 4 | |
| 960 // TODO(ascull): is .long portable? | |
| 961 Str << "\n\t.section\t.rodata." | |
| 962 << Func->getFunctionName() << "$jumptable,\"a\",@progbits\n" | |
| 963 << "\t.align 4\n" | |
| 964 << getName(Func) << ":"; | |
| 965 for (SizeT I = 0; I < NumTargets; ++I) | |
| 966 Str << "\n\t.long\t" << Targets[I]->getAsmName(); | |
| 967 Str << "\n\n\t.text"; | |
| 968 } | |
| 969 void InstJumpTable::emitIAS(const Cfg *Func) const { | |
|
jvoung (off chromium)
2015/07/15 18:32:01
add a newline between functions
ascull
2015/07/16 19:38:45
Done.
| |
| 970 // TODO(ascull): put jump table in the global context for emision later | |
|
jvoung (off chromium)
2015/07/15 18:32:01
emision -> emission
ascull
2015/07/16 19:38:45
Done.
| |
| 971 (void)Func; | |
| 972 } | |
| 973 | |
| 974 void InstJumpTable::dump(const Cfg *Func) const { | |
| 975 if (!BuildDefs::dump()) | |
| 976 return; | |
| 977 Ostream &Str = Func->getContext()->getStrDump(); | |
| 978 Str << "jump table ["; | |
| 979 for (SizeT I = 0; I < NumTargets; ++I) | |
| 980 Str << "\n " << Targets[I]->getName(); | |
| 981 Str << "\n ]"; | |
| 982 } | |
| 983 | |
| 920 void InstTarget::dump(const Cfg *Func) const { | 984 void InstTarget::dump(const Cfg *Func) const { |
| 921 if (!BuildDefs::dump()) | 985 if (!BuildDefs::dump()) |
| 922 return; | 986 return; |
| 923 Ostream &Str = Func->getContext()->getStrDump(); | 987 Ostream &Str = Func->getContext()->getStrDump(); |
| 924 Str << "[TARGET] "; | 988 Str << "[TARGET] "; |
| 925 Inst::dump(Func); | 989 Inst::dump(Func); |
| 926 } | 990 } |
| 927 | 991 |
| 928 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) { | 992 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) { |
| 929 const auto SrcVar = llvm::dyn_cast<const Variable>(Source); | 993 const auto SrcVar = llvm::dyn_cast<const Variable>(Source); |
| 930 if (!SrcVar) | 994 if (!SrcVar) |
| 931 return false; | 995 return false; |
| 932 if (Dest->hasReg() && Dest->getRegNum() == SrcVar->getRegNum()) { | 996 if (Dest->hasReg() && Dest->getRegNum() == SrcVar->getRegNum()) { |
| 933 // TODO: On x86-64, instructions like "mov eax, eax" are used to | 997 // 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 | 998 // clear the upper 32 bits of rax. We need to recognize and |
| 935 // preserve these. | 999 // preserve these. |
| 936 return true; | 1000 return true; |
| 937 } | 1001 } |
| 938 if (!Dest->hasReg() && !SrcVar->hasReg() && | 1002 if (!Dest->hasReg() && !SrcVar->hasReg() && |
| 939 Dest->getStackOffset() == SrcVar->getStackOffset()) | 1003 Dest->getStackOffset() == SrcVar->getStackOffset()) |
| 940 return true; | 1004 return true; |
| 941 return false; | 1005 return false; |
| 942 } | 1006 } |
| 943 | 1007 |
| 944 } // end of namespace Ice | 1008 } // end of namespace Ice |
| OLD | NEW |