OLD | NEW |
1 //===- subzero/src/IceCfgNode.cpp - Basic block (node) implementation -----===// | 1 //===- subzero/src/IceCfgNode.cpp - Basic block (node) 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 // This file implements the CfgNode class, including the complexities | 10 // This file implements the CfgNode class, including the complexities |
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
827 Str << ","; | 827 Str << ","; |
828 Var->emit(Func); | 828 Var->emit(Func); |
829 First = false; | 829 First = false; |
830 } | 830 } |
831 } | 831 } |
832 } | 832 } |
833 } | 833 } |
834 } | 834 } |
835 | 835 |
836 void updateStats(Cfg *Func, const Inst *I) { | 836 void updateStats(Cfg *Func, const Inst *I) { |
| 837 if (!ALLOW_DUMP) |
| 838 return; |
837 // Update emitted instruction count, plus fill/spill count for | 839 // Update emitted instruction count, plus fill/spill count for |
838 // Variable operands without a physical register. | 840 // Variable operands without a physical register. |
839 if (uint32_t Count = I->getEmitInstCount()) { | 841 if (uint32_t Count = I->getEmitInstCount()) { |
840 Func->getContext()->statsUpdateEmitted(Count); | 842 Func->getContext()->statsUpdateEmitted(Count); |
841 if (Variable *Dest = I->getDest()) { | 843 if (Variable *Dest = I->getDest()) { |
842 if (!Dest->hasReg()) | 844 if (!Dest->hasReg()) |
843 Func->getContext()->statsUpdateFills(); | 845 Func->getContext()->statsUpdateFills(); |
844 } | 846 } |
845 for (SizeT S = 0; S < I->getSrcSize(); ++S) { | 847 for (SizeT S = 0; S < I->getSrcSize(); ++S) { |
846 if (Variable *Src = llvm::dyn_cast<Variable>(I->getSrc(S))) { | 848 if (Variable *Src = llvm::dyn_cast<Variable>(I->getSrc(S))) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
884 I.emit(Func); | 886 I.emit(Func); |
885 if (DecorateAsm) | 887 if (DecorateAsm) |
886 emitLiveRangesEnded(Str, Func, &I, LiveRegCount); | 888 emitLiveRangesEnded(Str, Func, &I, LiveRegCount); |
887 Str << "\n"; | 889 Str << "\n"; |
888 updateStats(Func, &I); | 890 updateStats(Func, &I); |
889 } | 891 } |
890 if (DecorateAsm) | 892 if (DecorateAsm) |
891 emitRegisterUsage(Str, Func, this, false, LiveRegCount); | 893 emitRegisterUsage(Str, Func, this, false, LiveRegCount); |
892 } | 894 } |
893 | 895 |
| 896 // Helper class for emitIAS(). |
| 897 namespace { |
| 898 class BundleEmitHelper { |
| 899 BundleEmitHelper() = delete; |
| 900 BundleEmitHelper(const BundleEmitHelper &) = delete; |
| 901 BundleEmitHelper &operator=(const BundleEmitHelper &) = delete; |
| 902 |
| 903 public: |
| 904 BundleEmitHelper(Assembler *Asm, const InstList &Insts) |
| 905 : Asm(Asm), End(Insts.end()), BundleLockStart(End), |
| 906 BundleSize(1 << Asm->getBundleAlignLog2Bytes()), |
| 907 BundleMaskLo(BundleSize - 1), BundleMaskHi(~BundleMaskLo), |
| 908 SizeSnapshotPre(0), SizeSnapshotPost(0) {} |
| 909 // Check whether we're currently within a bundle_lock region. |
| 910 bool isInBundleLockRegion() const { return BundleLockStart != End; } |
| 911 // Check whether the current bundle_lock region has the align_to_end |
| 912 // option. |
| 913 bool isAlignToEnd() const { |
| 914 assert(isInBundleLockRegion()); |
| 915 return llvm::cast<InstBundleLock>(getBundleLockStart())->getOption() == |
| 916 InstBundleLock::Opt_AlignToEnd; |
| 917 } |
| 918 // Check whether the entire bundle_lock region falls within the same |
| 919 // bundle. |
| 920 bool isSameBundle() const { |
| 921 assert(isInBundleLockRegion()); |
| 922 return SizeSnapshotPre == SizeSnapshotPost || |
| 923 (SizeSnapshotPre & BundleMaskHi) == |
| 924 ((SizeSnapshotPost - 1) & BundleMaskHi); |
| 925 } |
| 926 // Get the bundle alignment of the first instruction of the |
| 927 // bundle_lock region. |
| 928 intptr_t getPreAlignment() const { |
| 929 assert(isInBundleLockRegion()); |
| 930 return SizeSnapshotPre & BundleMaskLo; |
| 931 } |
| 932 // Get the bundle alignment of the first instruction past the |
| 933 // bundle_lock region. |
| 934 intptr_t getPostAlignment() const { |
| 935 assert(isInBundleLockRegion()); |
| 936 return SizeSnapshotPost & BundleMaskLo; |
| 937 } |
| 938 // Get the iterator pointing to the bundle_lock instruction, e.g. to |
| 939 // roll back the instruction iteration to that point. |
| 940 InstList::const_iterator getBundleLockStart() const { |
| 941 assert(isInBundleLockRegion()); |
| 942 return BundleLockStart; |
| 943 } |
| 944 // Set up bookkeeping when the bundle_lock instruction is first |
| 945 // processed. |
| 946 void enterBundleLock(InstList::const_iterator I) { |
| 947 assert(!isInBundleLockRegion()); |
| 948 BundleLockStart = I; |
| 949 SizeSnapshotPre = Asm->getBufferSize(); |
| 950 Asm->setPreliminary(true); |
| 951 assert(isInBundleLockRegion()); |
| 952 } |
| 953 // Update bookkeeping when the bundle_unlock instruction is |
| 954 // processed. |
| 955 void enterBundleUnlock() { |
| 956 assert(isInBundleLockRegion()); |
| 957 SizeSnapshotPost = Asm->getBufferSize(); |
| 958 } |
| 959 // Update bookkeeping when we are completely finished with the |
| 960 // bundle_lock region. |
| 961 void leaveBundleLockRegion() { BundleLockStart = End; } |
| 962 // Check whether the instruction sequence fits within the current |
| 963 // bundle, and if not, add nop padding to the end of the current |
| 964 // bundle. |
| 965 void padToNextBundle() { |
| 966 assert(isInBundleLockRegion()); |
| 967 if (!isSameBundle()) { |
| 968 intptr_t PadToNextBundle = BundleSize - getPreAlignment(); |
| 969 Asm->padWithNop(PadToNextBundle); |
| 970 SizeSnapshotPre += PadToNextBundle; |
| 971 SizeSnapshotPost += PadToNextBundle; |
| 972 assert((Asm->getBufferSize() & BundleMaskLo) == 0); |
| 973 assert(Asm->getBufferSize() == SizeSnapshotPre); |
| 974 } |
| 975 } |
| 976 // If align_to_end is specified, add padding such that the |
| 977 // instruction sequences ends precisely at a bundle boundary. |
| 978 void padForAlignToEnd() { |
| 979 assert(isInBundleLockRegion()); |
| 980 if (isAlignToEnd()) { |
| 981 if (intptr_t Offset = getPostAlignment()) { |
| 982 Asm->padWithNop(BundleSize - Offset); |
| 983 SizeSnapshotPre = Asm->getBufferSize(); |
| 984 } |
| 985 } |
| 986 } |
| 987 // Update bookkeeping when rolling back for the second pass. |
| 988 void rollback() { |
| 989 assert(isInBundleLockRegion()); |
| 990 Asm->setBufferSize(SizeSnapshotPre); |
| 991 Asm->setPreliminary(false); |
| 992 } |
| 993 |
| 994 private: |
| 995 Assembler *const Asm; |
| 996 // End is a sentinel value such that BundleLockStart==End implies |
| 997 // that we are not in a bundle_lock region. |
| 998 const InstList::const_iterator End; |
| 999 InstList::const_iterator BundleLockStart; |
| 1000 const intptr_t BundleSize; |
| 1001 // Masking with BundleMaskLo identifies an address's bundle offset. |
| 1002 const intptr_t BundleMaskLo; |
| 1003 // Masking with BundleMaskHi identifies an address's bundle. |
| 1004 const intptr_t BundleMaskHi; |
| 1005 intptr_t SizeSnapshotPre; |
| 1006 intptr_t SizeSnapshotPost; |
| 1007 }; |
| 1008 |
| 1009 } // end of anonymous namespace |
| 1010 |
894 void CfgNode::emitIAS(Cfg *Func) const { | 1011 void CfgNode::emitIAS(Cfg *Func) const { |
895 Func->setCurrentNode(this); | 1012 Func->setCurrentNode(this); |
896 Assembler *Asm = Func->getAssembler<>(); | 1013 Assembler *Asm = Func->getAssembler<>(); |
| 1014 // TODO(stichnot): When sandboxing, defer binding the node label |
| 1015 // until just before the first instruction is emitted, to reduce the |
| 1016 // chance that a padding nop is a branch target. |
897 Asm->BindCfgNodeLabel(getIndex()); | 1017 Asm->BindCfgNodeLabel(getIndex()); |
898 for (const Inst &I : Phis) { | 1018 for (const Inst &I : Phis) { |
899 if (I.isDeleted()) | 1019 if (I.isDeleted()) |
900 continue; | 1020 continue; |
901 // Emitting a Phi instruction should cause an error. | 1021 // Emitting a Phi instruction should cause an error. |
902 I.emitIAS(Func); | 1022 I.emitIAS(Func); |
903 } | 1023 } |
904 for (const Inst &I : Insts) { | 1024 |
905 if (I.isDeleted()) | 1025 // Do the simple emission if not sandboxed. |
| 1026 if (!Func->getContext()->getFlags().getUseSandboxing()) { |
| 1027 for (const Inst &I : Insts) { |
| 1028 if (!I.isDeleted() && !I.isRedundantAssign()) { |
| 1029 I.emitIAS(Func); |
| 1030 updateStats(Func, &I); |
| 1031 } |
| 1032 } |
| 1033 return; |
| 1034 } |
| 1035 |
| 1036 // The remainder of the function handles emission with sandboxing. |
| 1037 // There are explicit bundle_lock regions delimited by bundle_lock |
| 1038 // and bundle_unlock instructions. All other instructions are |
| 1039 // treated as an implicit one-instruction bundle_lock region. |
| 1040 // Emission is done twice for each bundle_lock region. The first |
| 1041 // pass is a preliminary pass, after which we can figure out what |
| 1042 // nop padding is needed, then roll back, and make the final pass. |
| 1043 // |
| 1044 // Ideally, the first pass would be speculative and the second pass |
| 1045 // would only be done if nop padding were needed, but the structure |
| 1046 // of the integrated assembler makes it hard to roll back the state |
| 1047 // of label bindings, label links, and relocation fixups. Instead, |
| 1048 // the first pass just disables all mutation of that state. |
| 1049 |
| 1050 BundleEmitHelper Helper(Asm, Insts); |
| 1051 InstList::const_iterator End = Insts.end(); |
| 1052 // Retrying indicates that we had to roll back to the bundle_lock |
| 1053 // instruction to apply padding before the bundle_lock sequence. |
| 1054 bool Retrying = false; |
| 1055 for (InstList::const_iterator I = Insts.begin(); I != End; ++I) { |
| 1056 if (I->isDeleted() || I->isRedundantAssign()) |
906 continue; | 1057 continue; |
907 if (I.isRedundantAssign()) | 1058 |
| 1059 if (llvm::isa<InstBundleLock>(I)) { |
| 1060 // Set up the initial bundle_lock state. This should not happen |
| 1061 // while retrying, because the retry rolls back to the |
| 1062 // instruction following the bundle_lock instruction. |
| 1063 assert(!Retrying); |
| 1064 Helper.enterBundleLock(I); |
908 continue; | 1065 continue; |
909 I.emitIAS(Func); | 1066 } |
910 updateStats(Func, &I); | 1067 |
| 1068 if (llvm::isa<InstBundleUnlock>(I)) { |
| 1069 Helper.enterBundleUnlock(); |
| 1070 if (Retrying) { |
| 1071 // Make sure all instructions are in the same bundle. |
| 1072 assert(Helper.isSameBundle()); |
| 1073 // If align_to_end is specified, make sure the next |
| 1074 // instruction begins the bundle. |
| 1075 assert(!Helper.isAlignToEnd() || Helper.getPostAlignment() == 0); |
| 1076 Helper.leaveBundleLockRegion(); |
| 1077 Retrying = false; |
| 1078 } else { |
| 1079 // This is the first pass, so roll back for the retry pass. |
| 1080 Helper.rollback(); |
| 1081 // Pad to the next bundle if the instruction sequence crossed |
| 1082 // a bundle boundary. |
| 1083 Helper.padToNextBundle(); |
| 1084 // Insert additional padding to make AlignToEnd work. |
| 1085 Helper.padForAlignToEnd(); |
| 1086 // Prepare for the retry pass after padding is done. |
| 1087 Retrying = true; |
| 1088 I = Helper.getBundleLockStart(); |
| 1089 } |
| 1090 continue; |
| 1091 } |
| 1092 |
| 1093 // I points to a non bundle_lock/bundle_unlock instruction. |
| 1094 if (Helper.isInBundleLockRegion()) { |
| 1095 I->emitIAS(Func); |
| 1096 // Only update stats during the final pass. |
| 1097 if (Retrying) |
| 1098 updateStats(Func, I); |
| 1099 } else { |
| 1100 // Treat it as though there were an implicit bundle_lock and |
| 1101 // bundle_unlock wrapping the instruction. |
| 1102 Helper.enterBundleLock(I); |
| 1103 I->emitIAS(Func); |
| 1104 Helper.enterBundleUnlock(); |
| 1105 Helper.rollback(); |
| 1106 Helper.padToNextBundle(); |
| 1107 I->emitIAS(Func); |
| 1108 updateStats(Func, I); |
| 1109 Helper.leaveBundleLockRegion(); |
| 1110 } |
911 } | 1111 } |
| 1112 |
| 1113 // Don't allow bundle locking across basic blocks, to keep the |
| 1114 // backtracking mechanism simple. |
| 1115 assert(!Helper.isInBundleLockRegion()); |
| 1116 assert(!Retrying); |
912 } | 1117 } |
913 | 1118 |
914 void CfgNode::dump(Cfg *Func) const { | 1119 void CfgNode::dump(Cfg *Func) const { |
915 if (!ALLOW_DUMP) | 1120 if (!ALLOW_DUMP) |
916 return; | 1121 return; |
917 Func->setCurrentNode(this); | 1122 Func->setCurrentNode(this); |
918 Ostream &Str = Func->getContext()->getStrDump(); | 1123 Ostream &Str = Func->getContext()->getStrDump(); |
919 Liveness *Liveness = Func->getLiveness(); | 1124 Liveness *Liveness = Func->getLiveness(); |
920 if (Func->isVerbose(IceV_Instructions)) { | 1125 if (Func->isVerbose(IceV_Instructions)) { |
921 Str << getName() << ":\n"; | 1126 Str << getName() << ":\n"; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
985 if (!First) | 1190 if (!First) |
986 Str << ", "; | 1191 Str << ", "; |
987 First = false; | 1192 First = false; |
988 Str << "%" << I->getName(); | 1193 Str << "%" << I->getName(); |
989 } | 1194 } |
990 Str << "\n"; | 1195 Str << "\n"; |
991 } | 1196 } |
992 } | 1197 } |
993 | 1198 |
994 } // end of namespace Ice | 1199 } // end of namespace Ice |
OLD | NEW |