Index: llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp +++ llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp @@ -1086,6 +1086,8 @@ unsigned StartOp = 2 + 2; // Use all the operands. unsigned NumOffset = 0; + // Amount of SP adjustment folded into a push. + unsigned Pad = 0; switch (Opc) { default: @@ -1107,6 +1109,16 @@ // temporary to workaround PR11902. if (MO.isImplicit()) continue; + // Registers, pushed as a part of folding an SP update into the + // push instruction are marked as undef and should not be + // restored when unwinding, because the function can modify the + // corresponding stack slots. + if (MO.isUndef()) { + assert(RegList.empty() && + "Pad registers must come before restored ones"); + Pad += 4; + continue; + } RegList.push_back(MO.getReg()); } break; @@ -1118,8 +1130,12 @@ RegList.push_back(SrcReg); break; } - if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM) + if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM) { ATS.emitRegSave(RegList, Opc == ARM::VSTMDDB_UPD); + // Account for the SP adjustment, folded into the push. + if (Pad) + ATS.emitPad(Pad); + } } else { // Changes of stack / frame pointer. if (SrcReg == ARM::SP) { Index: llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp =================================================================== --- llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -2277,9 +2277,9 @@ --CurRegEnc) { unsigned CurReg = RegClass->getRegister(CurRegEnc); if (!IsPop) { - // Pushing any register is completely harmless, mark the - // register involved as undef since we don't care about it in - // the slightest. + // Pushing any register is completely harmless, mark the register involved + // as undef since we don't care about its value and must not restore it + // during stack unwinding. RegList.push_back(MachineOperand::CreateReg(CurReg, false, false, false, false, true)); --RegsNeeded; Index: llvm/trunk/test/CodeGen/ARM/PR35379.ll =================================================================== --- llvm/trunk/test/CodeGen/ARM/PR35379.ll +++ llvm/trunk/test/CodeGen/ARM/PR35379.ll @@ -0,0 +1,52 @@ +; RUN: llc -mtriple=armv7a-eabi < %s | FileCheck %s --check-prefix=CHECK-ARM +; RUN: llc -mtriple=armv6m-eabi < %s | FileCheck %s --check-prefix=CHECK-THM + +; Function Attrs: minsize optsize +declare void @g(i32*) local_unnamed_addr #0 + +; Function Attrs: minsize optsize +define void @f() local_unnamed_addr #0 { +entry: + %i = alloca i32, align 4 + %0 = bitcast i32* %i to i8* + store i32 1, i32* %i, align 4 + call void @g(i32* nonnull %i) + ret void +} + +; Check unwind info does not mention the registers used for padding, and +; the amount of stack adjustment is the same as in the actual +; instructions. + +; CHECK-ARM: .save {r11, lr} +; CHECK-ARM-NEXT: .pad #8 +; CHECK-ARM-NEXT: push {r9, r10, r11, lr} +; CHECK-ARM: pop {r2, r3, r11, pc} + +; CHECK-THM: .save {r7, lr} +; CHECK-THM-NEXT: .pad #8 +; CHECK-THM-NEXT: push {r5, r6, r7, lr} +; CHECK-THM: pop {r2, r3, r7, pc} + + +define void @f1() local_unnamed_addr #1 { +entry: + %i = alloca i32, align 4 + %0 = bitcast i32* %i to i8* + store i32 1, i32* %i, align 4 + call void @g(i32* nonnull %i) + ret void +} + +; Check that unwind info is the same whether or not using -Os (minsize attr) + +; CHECK-ARM: .save {r11, lr} +; CHECK-ARM-NEXT: push {r11, lr} +; CHECK-ARM-NEXT: .pad #8 + +; CHECK-THM: .save {r7, lr} +; CHECK-THM-NEXT: push {r7, lr} +; CHECK-THM-NEXT: .pad #8 + +attributes #0 = { minsize optsize } +attributes #1 = { optsize }