Index: lib/CodeGen/SjLjEHPrepare.cpp =================================================================== --- lib/CodeGen/SjLjEHPrepare.cpp +++ lib/CodeGen/SjLjEHPrepare.cpp @@ -248,19 +248,38 @@ for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI != AE; ++AI) { Type *Ty = AI->getType(); - - // Aggregate types can't be cast, but are legal argument types, so we have - // to handle them differently. We use an extract/insert pair as a - // lightweight method to achieve the same goal. - if (isa(Ty) || isa(Ty)) { - Instruction *EI = ExtractValueInst::Create(AI, 0, "", AfterAllocaInsPt); - Instruction *NI = InsertValueInst::Create(AI, EI, 0); - NI->insertAfter(EI); - AI->replaceAllUsesWith(NI); - - // Set the operand of the instructions back to the AllocaInst. - EI->setOperand(0, AI); - NI->setOperand(0, AI); + StructType *ST = dyn_cast(Ty); + ArrayType *AT = dyn_cast(Ty); + + if (ST || AT) { + // Aggregate types can't be cast, but are legal argument types, so we have + // to handle them differently. We use an always true selection to achieve + // the same goal + if ((ST && ST->getNumElements() != 0) + || (AT && AT->getNumElements() != 0)) { + Instruction *EI = ExtractValueInst::Create(AI, 0, "", AfterAllocaInsPt); + Instruction *NI = InsertValueInst::Create(AI, EI, 0); + NI->insertAfter(EI); + AI->replaceAllUsesWith(NI); + + // Set the operand of the instructions back to the AllocaInst. + EI->setOperand(0, AI); + NI->setOperand(0, AI); + } else { + // If it is empty structure or 0-length array it is impossible + // to use ExtractValue/InsertValue pair, so instead + // always-true select is used against arg and reconstructed + // from null value + Value *NullValue = ConstantPointerNull::get(Ty->getPointerTo()); + + Instruction *LI = new LoadInst(NullValue, AI->getName() + ".null", AfterAllocaInsPt); + Value *TrueValue = ConstantInt::getTrue(F.getContext()); + Instruction *SI = SelectInst::Create(TrueValue, AI, LI); + SI->insertAfter(LI); + AI->replaceAllUsesWith(SI); + + SI->setOperand(1, AI); + } } else { // This is always a no-op cast because we're casting AI to AI->getType() // so src and destination types are identical. BitCast is the only Index: test/CodeGen/Arm/sjljehprepare-lower-empty-struct.ll =================================================================== --- /dev/null +++ test/CodeGen/Arm/sjljehprepare-lower-empty-struct.ll @@ -0,0 +1,31 @@ +; RUN: llc -mtriple=armv7-apple-ios -O0 < %s | FileCheck %s +; RUN: llc -mtriple=armv7-apple-ios -O1 < %s | FileCheck %s +; RUN: llc -mtriple=armv7-apple-ios -O2 < %s | FileCheck %s +; RUN: llc -mtriple=armv7-apple-ios -O3 < %s | FileCheck %s + +; SjLjEHPrepare shouldn't crash when lowering empty structs. +; +; Checks that between in case of empty structs used as arguments +; nothing happens, i.e. there are no instructions between +; __Unwind_SjLj_Register and actual @bar invocation + + +define i8* @foo({} %c) { +entry: +; CHECK: bl __Unwind_SjLj_Register +; CHECK-NEXT: {{[A-Z][a-zA-Z0-9]*}}: +; CHECK-NEXT: bl _bar + invoke void @bar () + to label %unreachable unwind label %handler + +unreachable: + unreachable + +handler: + %tmp = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @baz to i8*) + cleanup + resume { i8*, i32 } undef +} + +declare void @bar() +declare i32 @baz(...)