@@ -74,6 +74,20 @@ void InsertNegateRAState::runOnFunction(BinaryFunction &BF) {
7474 }
7575}
7676
77+ void InsertNegateRAState::inferUnknownStates (BinaryFunction &BF) {
78+ BinaryContext &BC = BF.getBinaryContext ();
79+
80+ // Fill in missing RAStates in simple cases (inside BBs).
81+ for (BinaryBasicBlock &BB : BF) {
82+ fillUnknownStateInBB (BC, BB);
83+ }
84+ // Some stubs have no predecessors. For those, we iterate once in the layout
85+ // order to fill their RAState.
86+ fillUnknownStubs (BF);
87+
88+ fillUnknownBlocksInCFG (BF);
89+ }
90+
7791void InsertNegateRAState::coverFunctionFragmentStart (BinaryFunction &BF,
7892 FunctionFragment &FF) {
7993 BinaryContext &BC = BF.getBinaryContext ();
@@ -104,32 +118,201 @@ void InsertNegateRAState::coverFunctionFragmentStart(BinaryFunction &BF,
104118 MCCFIInstruction::createNegateRAState (nullptr ));
105119}
106120
107- void InsertNegateRAState::inferUnknownStates (BinaryFunction &BF) {
121+ std::optional<bool >
122+ InsertNegateRAState::getFirstKnownRAState (BinaryContext &BC,
123+ BinaryBasicBlock &BB) {
124+ for (const MCInst &Inst : BB) {
125+ if (BC.MIB ->isCFI (Inst))
126+ continue ;
127+ auto RAStateOpt = BC.MIB ->getRAState (Inst);
128+ if (RAStateOpt)
129+ return RAStateOpt;
130+ }
131+ return std::nullopt ;
132+ }
133+
134+ void InsertNegateRAState::fillUnknownStateInBB (BinaryContext &BC,
135+ BinaryBasicBlock &BB) {
136+
137+ auto First = BB.getFirstNonPseudo ();
138+ if (First == BB.end ())
139+ return ;
140+ // If the first instruction has unknown RAState, we should copy the first
141+ // known RAState.
142+ auto RAStateOpt = BC.MIB ->getRAState (*First);
143+ if (!RAStateOpt) {
144+ auto FirstRAState = getFirstKnownRAState (BC, BB);
145+ if (!FirstRAState)
146+ // We fill unknown BBs later.
147+ return ;
148+
149+ BC.MIB ->setRAState (*First, *FirstRAState);
150+ }
151+
152+ // At this point we know the RAState of the first instruction,
153+ // so we can propagate the RAStates to all subsequent unknown instructions.
154+ MCInst Prev = *First;
155+ for (auto It = BB.begin () + 1 ; It != BB.end (); ++It) {
156+ MCInst &Inst = *It;
157+ if (BC.MIB ->isCFI (Inst))
158+ continue ;
159+
160+ auto PrevRAState = BC.MIB ->getRAState (Prev);
161+ if (!PrevRAState)
162+ llvm_unreachable (" Previous Instruction has no RAState." );
163+
164+ auto RAState = BC.MIB ->getRAState (Inst);
165+ if (!RAState) {
166+ if (BC.MIB ->isPSignOnLR (Prev))
167+ PrevRAState = true ;
168+ else if (BC.MIB ->isPAuthOnLR (Prev))
169+ PrevRAState = false ;
170+ BC.MIB ->setRAState (Inst, *PrevRAState);
171+ }
172+ Prev = Inst;
173+ }
174+ }
175+
176+ bool InsertNegateRAState::isUnknownBlock (BinaryContext &BC,
177+ BinaryBasicBlock &BB) {
178+ for (const MCInst &Inst : BB) {
179+ if (BC.MIB ->isCFI (Inst))
180+ continue ;
181+ auto RAState = BC.MIB ->getRAState (Inst);
182+ if (RAState)
183+ return false ;
184+ }
185+ return true ;
186+ }
187+
188+ void InsertNegateRAState::markUnknownBlock (BinaryContext &BC,
189+ BinaryBasicBlock &BB, bool State) {
190+ // If we call this when an Instruction has either kRASigned or kRAUnsigned
191+ // annotation, setRASigned or setRAUnsigned would fail.
192+ assert (isUnknownBlock (BC, BB) &&
193+ " markUnknownBlock should only be called on unknown blocks" );
194+ for (MCInst &Inst : BB) {
195+ if (BC.MIB ->isCFI (Inst))
196+ continue ;
197+ BC.MIB ->setRAState (Inst, State);
198+ }
199+ }
200+
201+ std::optional<bool > InsertNegateRAState::getRAStateByCFG (BinaryBasicBlock &BB,
202+ BinaryFunction &BF) {
108203 BinaryContext &BC = BF.getBinaryContext ();
109- bool FirstIter = true ;
110- MCInst PrevInst;
111- for (BinaryBasicBlock &BB : BF) {
112- for (MCInst &Inst : BB) {
113- if (BC.MIB ->isCFI (Inst))
204+
205+ auto checkRAState = [&](std::optional<bool > &NeighborRAState, MCInst &Inst) {
206+ auto RAState = BC.MIB ->getRAState (Inst);
207+ if (!RAState)
208+ return ;
209+ if (!NeighborRAState) {
210+ NeighborRAState = *RAState;
211+ return ;
212+ }
213+ if (NeighborRAState != *RAState) {
214+ BC.outs () << " BOLT-WARNING: Conflicting RAState found in function "
215+ << BF.getPrintName () << " . Function will not be optimized.\n " ;
216+ BF.setIgnored ();
217+ }
218+ };
219+
220+ // Holds the first found RAState from CFG neighbors.
221+ std::optional<bool > NeighborRAState = std::nullopt ;
222+ if (BB.pred_size () != 0 ) {
223+ for (BinaryBasicBlock *PredBB : BB.predecessors ()) {
224+ // find last inst of Predecessor with known RA State.
225+ auto LI = PredBB->getLastNonPseudo ();
226+ if (LI == PredBB->rend ())
227+ continue ;
228+ MCInst &LastInst = *LI;
229+ checkRAState (NeighborRAState, LastInst);
230+ }
231+ } else if (BB.succ_size () != 0 ) {
232+ for (BinaryBasicBlock *SuccBB : BB.successors ()) {
233+ // find first inst of Successor with known RA State.
234+ auto FI = SuccBB->getFirstNonPseudo ();
235+ if (FI == SuccBB->end ())
114236 continue ;
237+ MCInst &FirstInst = *FI;
238+ checkRAState (NeighborRAState, FirstInst);
239+ }
240+ } else {
241+ llvm_unreachable (" Called getRAStateByCFG on a BB with no preds or succs." );
242+ }
243+
244+ return NeighborRAState;
245+ }
115246
116- auto RAState = BC.MIB ->getRAState (Inst);
117- if (!FirstIter && !RAState) {
118- if (BC.MIB ->isPSignOnLR (PrevInst))
119- RAState = true ;
120- else if (BC.MIB ->isPAuthOnLR (PrevInst))
121- RAState = false ;
122- else {
247+ void InsertNegateRAState::fillUnknownStubs (BinaryFunction &BF) {
248+ BinaryContext &BC = BF.getBinaryContext ();
249+ bool FirstIter = true ;
250+ MCInst PrevInst;
251+ for (FunctionFragment &FF : BF.getLayout ().fragments ()) {
252+ for (BinaryBasicBlock *BB : FF) {
253+ if (!FirstIter && isUnknownBlock (BC, *BB)) {
254+ // If we have no predecessors or successors, current BB is a Stub called
255+ // from another BinaryFunction. As of #160989, we have to copy the
256+ // PrevInst's RAState, because CFIs are already incorrect here.
257+ if (BB->pred_size () == 0 && BB->succ_size () == 0 ) {
123258 auto PrevRAState = BC.MIB ->getRAState (PrevInst);
124- RAState = PrevRAState ? *PrevRAState : false ;
259+ if (!PrevRAState) {
260+ llvm_unreachable (
261+ " Previous Instruction has no RAState in fillUnknownStubs." );
262+ continue ;
263+ }
264+
265+ if (BC.MIB ->isPSignOnLR (PrevInst)) {
266+ PrevRAState = true ;
267+ } else if (BC.MIB ->isPAuthOnLR (PrevInst)) {
268+ PrevRAState = false ;
269+ }
270+ markUnknownBlock (BC, *BB, *PrevRAState);
125271 }
126- BC. MIB -> setRAState (Inst, *RAState);
127- } else {
272+ }
273+ if (FirstIter) {
128274 FirstIter = false ;
129- if (!RAState )
130- BC. MIB -> setRAState (Inst, BF. getInitialRAState () );
275+ if (isUnknownBlock (BC, *BB) )
276+ markUnknownBlock (BC, *BB, false );
131277 }
132- PrevInst = Inst;
278+ auto Last = BB->getLastNonPseudo ();
279+ if (Last != BB->rend ())
280+ PrevInst = *Last;
281+ }
282+ }
283+ }
284+ void InsertNegateRAState::fillUnknownBlocksInCFG (BinaryFunction &BF) {
285+ BinaryContext &BC = BF.getBinaryContext ();
286+
287+ auto fillUnknowns = [&](BinaryFunction &BF) -> std::pair<int , bool > {
288+ int Unknowns = 0 ;
289+ bool Updated = false ;
290+ for (BinaryBasicBlock &BB : BF) {
291+ // Only try to iterate if the BB has either predecessors or successors.
292+ if (isUnknownBlock (BC, BB) &&
293+ (BB.pred_size () != 0 || BB.succ_size () != 0 )) {
294+ auto RAStateOpt = getRAStateByCFG (BB, BF);
295+ if (RAStateOpt) {
296+ markUnknownBlock (BC, BB, *RAStateOpt);
297+ Updated = true ;
298+ } else {
299+ Unknowns++;
300+ }
301+ }
302+ }
303+ return std::pair<int , bool >{Unknowns, Updated};
304+ };
305+
306+ while (true ) {
307+ std::pair<int , bool > Iter = fillUnknowns (BF);
308+ if (Iter.first == 0 )
309+ break ;
310+ if (!Iter.second ) {
311+ BC.errs () << " BOLT-WARNING: Could not infer RAState for " << Iter.first
312+ << " BBs in function " << BF.getPrintName ()
313+ << " . Function will not be optimized.\n " ;
314+ BF.setIgnored ();
315+ break ;
133316 }
134317 }
135318}
0 commit comments