@@ -68,6 +68,9 @@ class IRBuilder : public IRBuilderBase {
6868#endif
6969 {}
7070
71+ // / Defined below.
72+ class SavedInsertionPointRAII ;
73+
7174 // / Determines if the current location is apparently reachable. The
7275 // / invariant we maintain is that the insertion point of the builder
7376 // / always points within a block unless the current location is
@@ -345,6 +348,72 @@ class IRBuilder : public IRBuilderBase {
345348 }
346349 return result;
347350 }
351+
352+ bool insertingAtEndOfBlock () const {
353+ assert (hasValidIP () && " Must have insertion point to ask about it" );
354+ return InsertPt == BB->end ();
355+ }
356+ };
357+
358+ // / Given a Builder as input to its constructor, this class resets the Builder
359+ // / so it has the same insertion point at end of scope.
360+ class IRBuilder ::SavedInsertionPointRAII {
361+ IRBuilder &builder;
362+ PointerUnion<llvm::Instruction *, llvm::BasicBlock *> savedInsertionPoint;
363+
364+ public:
365+ // / Constructor that saves a Builder's insertion point without changing the
366+ // / builder's underlying insertion point.
367+ SavedInsertionPointRAII (IRBuilder &inputBuilder)
368+ : builder(inputBuilder), savedInsertionPoint() {
369+ // If our builder does not have a valid insertion point, just put nullptr
370+ // into SavedIP.
371+ if (!builder.hasValidIP ()) {
372+ savedInsertionPoint = static_cast <llvm::BasicBlock *>(nullptr );
373+ return ;
374+ }
375+
376+ // If we are inserting into the end of the block, stash the insertion block.
377+ if (builder.insertingAtEndOfBlock ()) {
378+ savedInsertionPoint = builder.GetInsertBlock ();
379+ return ;
380+ }
381+
382+ // Otherwise, stash the instruction.
383+ auto *i = &*builder.GetInsertPoint ();
384+ savedInsertionPoint = i;
385+ }
386+
387+ SavedInsertionPointRAII (IRBuilder &b, llvm::Instruction *newInsertionPoint)
388+ : SavedInsertionPointRAII(b) {
389+ builder.SetInsertPoint (newInsertionPoint);
390+ }
391+
392+ SavedInsertionPointRAII (IRBuilder &b, llvm::BasicBlock *block,
393+ llvm::BasicBlock::iterator iter)
394+ : SavedInsertionPointRAII(b) {
395+ builder.SetInsertPoint (block, iter);
396+ }
397+
398+ SavedInsertionPointRAII (IRBuilder &b, llvm::BasicBlock *insertionBlock)
399+ : SavedInsertionPointRAII(b) {
400+ builder.SetInsertPoint (insertionBlock);
401+ }
402+
403+ SavedInsertionPointRAII (const SavedInsertionPointRAII &) = delete ;
404+ SavedInsertionPointRAII &operator =(const SavedInsertionPointRAII &) = delete ;
405+ SavedInsertionPointRAII (SavedInsertionPointRAII &&) = delete ;
406+ SavedInsertionPointRAII &operator =(SavedInsertionPointRAII &&) = delete ;
407+
408+ ~SavedInsertionPointRAII () {
409+ if (savedInsertionPoint.isNull ()) {
410+ builder.ClearInsertionPoint ();
411+ } else if (savedInsertionPoint.is <llvm::Instruction *>()) {
412+ builder.SetInsertPoint (savedInsertionPoint.get <llvm::Instruction *>());
413+ } else {
414+ builder.SetInsertPoint (savedInsertionPoint.get <llvm::BasicBlock *>());
415+ }
416+ }
348417};
349418
350419} // end namespace irgen
0 commit comments