diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -8866,6 +8866,7 @@ = catchswitch within [ label , label , ... ] unwind to caller = catchswitch within [ label , label , ... ] unwind label + = catchswitch within [ label , label , ... ] unwindabort Overview: """"""""" @@ -8892,9 +8893,12 @@ Semantics: """""""""" -Executing this instruction transfers control to one of the successors in -``handlers``, if appropriate, or continues to unwind via the unwind label if -present. +Executing this instruction transfers control to one of the successors +in ``handlers``, if appropriate. If no handler matches, continues to +unwind to the parent function (``unwind to caller``), to the +specified unwind label (``unwind label ``), or, aborts the +program (``unwindabort``). See also the description of ``unwindabort`` for the +:ref:`call ` instruction. The ``catchswitch`` is both a terminator and a "pad" instruction, meaning that it must be both the first non-phi instruction and last instruction in the basic diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -4343,6 +4343,7 @@ //===----------------------------------------------------------------------===// class CatchSwitchInst : public Instruction { using UnwindDestField = BoolBitfieldElementT<0>; + using UnwindAbortField = BoolBitfieldElementT<1>; /// The number of operands actually allocated. NumOperands is /// the number actually in use. @@ -4407,6 +4408,11 @@ void setParentPad(Value *ParentPad) { setOperand(0, ParentPad); } // Accessor Methods for CatchSwitch stmt + bool isUnwindAbort() const { return getSubclassData(); } + void setUnwindAbort(bool IsUA = true) { + setSubclassData(IsUA); + } + bool hasUnwindDest() const { return getSubclassData(); } bool unwindsToCaller() const { return !hasUnwindDest(); } BasicBlock *getUnwindDest() const { diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -6938,20 +6938,27 @@ if (parseToken(lltok::rsquare, "expected ']' after catchswitch labels")) return true; - if (parseToken(lltok::kw_unwind, "expected 'unwind' after catchswitch scope")) - return true; - + bool UnwindAbort = false; BasicBlock *UnwindBB = nullptr; - if (EatIfPresent(lltok::kw_to)) { - if (parseToken(lltok::kw_caller, "expected 'caller' in catchswitch")) - return true; + if (Lex.getKind() == lltok::kw_unwindabort) { + Lex.Lex(); + UnwindAbort = true; } else { - if (parseTypeAndBasicBlock(UnwindBB, PFS)) + if (parseToken(lltok::kw_unwind, + "expected 'unwind' after catchswitch scope")) return true; - } + if (EatIfPresent(lltok::kw_to)) { + if (parseToken(lltok::kw_caller, "expected 'caller' in catchswitch")) + return true; + } else { + if (parseTypeAndBasicBlock(UnwindBB, PFS)) + return true; + } + } auto *CatchSwitch = CatchSwitchInst::Create(ParentPad, UnwindBB, Table.size()); + CatchSwitch->setUnwindAbort(UnwindAbort); for (BasicBlock *DestBB : Table) CatchSwitch->addHandler(DestBB); Inst = CatchSwitch; diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5327,10 +5327,17 @@ } BasicBlock *UnwindDest = nullptr; + bool UnwindAbort = false; if (Idx + 1 == Record.size()) { - UnwindDest = getBasicBlock(Record[Idx++]); - if (!UnwindDest) - return error("Invalid record"); + if (Record[Idx] == FunctionBBs.size()) { + // Uses numBBs+1 as flag for unwindabort. + UnwindAbort = true; + } else { + UnwindDest = getBasicBlock(Record[Idx]); + if (!UnwindDest) + return error("Invalid record"); + } + Idx++; } if (Record.size() != Idx) @@ -5338,6 +5345,7 @@ auto *CatchSwitch = CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers); + CatchSwitch->setUnwindAbort(UnwindAbort); for (BasicBlock *Handler : Handlers) CatchSwitch->addHandler(Handler); I = CatchSwitch; diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3033,6 +3033,11 @@ if (CatchSwitch.hasUnwindDest()) Vals.push_back(VE.getValueID(CatchSwitch.getUnwindDest())); + else if (CatchSwitch.isUnwindAbort()) { + // The unwindabort destination is represented by an invalid (one-past-end) + // basic-block-id. + Vals.push_back(VE.getBasicBlocks().size()); + } break; } case Instruction::CallBr: { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -4183,11 +4183,15 @@ writeOperand(PadBB, /*PrintType=*/true); ++Op; } - Out << "] unwind "; - if (const BasicBlock *UnwindDest = CatchSwitch->getUnwindDest()) + Out << "]"; + if (CatchSwitch->isUnwindAbort()) { + Out << " unwindabort"; + } else if (const BasicBlock *UnwindDest = CatchSwitch->getUnwindDest()) { + Out << " unwind "; writeOperand(UnwindDest, /*PrintType=*/true); - else - Out << "to caller"; + } else { + Out << " unwind to caller"; + } } else if (const auto *FPI = dyn_cast(&I)) { Out << " within "; writeOperand(FPI->getParentPad(), /*PrintType=*/false); diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -1281,6 +1281,7 @@ : Instruction(CSI.getType(), Instruction::CatchSwitch, nullptr, CSI.getNumOperands()) { init(CSI.getParentPad(), CSI.getUnwindDest(), CSI.getNumOperands()); + setUnwindAbort(CSI.isUnwindAbort()); setNumHungOffUseOperands(ReservedSpace); Use *OL = getOperandList(); const Use *InOL = CSI.getOperandList(); diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -1192,9 +1192,11 @@ invoke void @f.ccc() to label %normal unwind label %catchswitch1 invoke void @f.ccc() to label %normal unwind label %catchswitch2 invoke void @f.ccc() to label %normal unwind label %catchswitch3 + invoke void @f.ccc() to label %normal unwind label %catchswitch4 catchswitch1: %cs1 = catchswitch within none [label %catchpad1] unwind to caller + ; CHECK: %cs1 = catchswitch within none [label %catchpad1] unwind to caller catchpad1: catchpad within %cs1 [] @@ -1204,6 +1206,7 @@ catchswitch2: %cs2 = catchswitch within none [label %catchpad2] unwind to caller + ; CHECK: %cs2 = catchswitch within none [label %catchpad2] unwind to caller catchpad2: catchpad within %cs2 [ptr %arg1] @@ -1213,6 +1216,7 @@ catchswitch3: %cs3 = catchswitch within none [label %catchpad3] unwind label %cleanuppad1 + ; CHECK: %cs3 = catchswitch within none [label %catchpad3] unwind label %cleanuppad1 catchpad3: catchpad within %cs3 [ptr %arg1, ptr %arg2] @@ -1226,6 +1230,16 @@ ; CHECK: %clean.1 = cleanuppad within none [] ; CHECK-NEXT: unreachable +catchswitch4: + %cs4 = catchswitch within none [label %catchpad4] unwindabort + ; CHECK: %cs4 = catchswitch within none [label %catchpad4] unwindabort + +catchpad4: + catchpad within %cs4 [ptr %arg1, ptr %arg2] + br label %normal + ; CHECK: catchpad within %cs4 [ptr %arg1, ptr %arg2] + ; CHECK-NEXT: br label %normal + normal: ret i32 0 }