From: Tim Northover Date: Wed, 28 Oct 2015 22:56:36 +0000 (+0000) Subject: ARM: add support for WatchOS's compact unwind information. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=ed754ee4a72676ed8b6a54b2450250ab62949ed0;p=oota-llvm.git ARM: add support for WatchOS's compact unwind information. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251573 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h index b9cea06161d..ec8627ca7c1 100644 --- a/include/llvm/MC/MCObjectFileInfo.h +++ b/include/llvm/MC/MCObjectFileInfo.h @@ -35,7 +35,13 @@ protected: /// without an associated EH frame section. bool SupportsCompactUnwindWithoutEHFrame; - /// Some encoding values for EH. + /// OmitDwarfIfHaveCompactUnwind - True if the target object file + /// supports having some functions with compact unwind and other with + /// dwarf unwind. + bool OmitDwarfIfHaveCompactUnwind; + + /// PersonalityEncoding, LSDAEncoding, TTypeEncoding - Some encoding values + /// for EH. unsigned PersonalityEncoding; unsigned LSDAEncoding; unsigned FDECFIEncoding; @@ -200,6 +206,10 @@ public: bool getSupportsCompactUnwindWithoutEHFrame() const { return SupportsCompactUnwindWithoutEHFrame; } + bool getOmitDwarfIfHaveCompactUnwind() const { + return OmitDwarfIfHaveCompactUnwind; + } + bool getCommDirectiveSupportsAlignment() const { return CommDirectiveSupportsAlignment; } diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index e964032b9d2..8be1f4cbda2 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -1536,6 +1536,7 @@ void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB, const MCSymbol *DummyDebugKey = nullptr; NeedsEHFrameSection = !MOFI->getSupportsCompactUnwindWithoutEHFrame(); + bool CanOmitDwarf = MOFI->getOmitDwarfIfHaveCompactUnwind(); for (unsigned i = 0, n = FrameArray.size(); i < n; ++i) { const MCDwarfFrameInfo &Frame = FrameArray[i]; @@ -1545,7 +1546,7 @@ void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB, FDEEnd = nullptr; } - if (!NeedsEHFrameSection && Frame.CompactUnwindEncoding != + if (CanOmitDwarf && Frame.CompactUnwindEncoding != MOFI->getCompactUnwindDwarfEHFrameOnly()) // Don't generate an EH frame if we don't need one. I.e., it's taken care // of by the compact unwind encoding. diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index 666a1c306c5..4c51c8363f3 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -29,6 +29,10 @@ static bool useCompactUnwind(const Triple &T) { if (T.getArch() == Triple::aarch64) return true; + // armv7k always has it. + if (T.isWatchOS()) + return true; + // Use it on newer version of OS X. if (T.isMacOSX() && !T.isMacOSXVersionLT(10, 6)) return true; @@ -48,6 +52,9 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(Triple T) { if (T.isOSDarwin() && T.getArch() == Triple::aarch64) SupportsCompactUnwindWithoutEHFrame = true; + if (T.isWatchOS()) + OmitDwarfIfHaveCompactUnwind = true; + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; LSDAEncoding = FDECFIEncoding = dwarf::DW_EH_PE_pcrel; @@ -193,9 +200,11 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(Triple T) { SectionKind::getReadOnly()); if (T.getArch() == Triple::x86_64 || T.getArch() == Triple::x86) - CompactUnwindDwarfEHFrameOnly = 0x04000000; + CompactUnwindDwarfEHFrameOnly = 0x04000000; // UNWIND_X86_64_MODE_DWARF else if (T.getArch() == Triple::aarch64) - CompactUnwindDwarfEHFrameOnly = 0x03000000; + CompactUnwindDwarfEHFrameOnly = 0x03000000; // UNWIND_ARM64_MODE_DWARF + else if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) + CompactUnwindDwarfEHFrameOnly = 0x04000000; // UNWIND_ARM_MODE_DWARF } // Debug Information. @@ -767,6 +776,7 @@ void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, CommDirectiveSupportsAlignment = true; SupportsWeakOmittedEHFrame = true; SupportsCompactUnwindWithoutEHFrame = false; + OmitDwarfIfHaveCompactUnwind = false; PersonalityEncoding = LSDAEncoding = FDECFIEncoding = TTypeEncoding = dwarf::DW_EH_PE_absptr; diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index c8d34a23b48..13f528517f1 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -813,9 +813,9 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM, setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); - if (!Subtarget->isTargetMachO()) { - // Non-MachO platforms may return values in these registers via the - // personality function. + if (!Subtarget->useSjLjEH()) { + // Platforms which do not use SjLj EH may return values in these registers + // via the personality function. setExceptionPointerRegister(ARM::R0); setExceptionSelectorRegister(ARM::R1); } @@ -889,7 +889,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM, setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom); - if (Subtarget->isTargetDarwin()) + if (Subtarget->useSjLjEH()) setLibcallName(RTLIB::UNWIND_RESUME, "_Unwind_SjLj_Resume"); setOperationAction(ISD::SETCC, MVT::i32, Expand); diff --git a/lib/Target/ARM/ARMSubtarget.cpp b/lib/Target/ARM/ARMSubtarget.cpp index 84d3ebcc681..50eb37890fd 100644 --- a/lib/Target/ARM/ARMSubtarget.cpp +++ b/lib/Target/ARM/ARMSubtarget.cpp @@ -151,6 +151,8 @@ void ARMSubtarget::initializeEnvironment() { UseNaClTrap = false; GenLongCalls = false; UnsafeFPMath = false; + UseSjLjEH = (isTargetDarwin() && + TargetTriple.getSubArch() != Triple::ARMSubArch_v7k); } void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { @@ -324,7 +326,10 @@ bool ARMSubtarget::enableAtomicExpand() const { } bool ARMSubtarget::useStride4VFPs(const MachineFunction &MF) const { - return isSwift() && !MF.getFunction()->optForMinSize(); + // For general targets, the prologue can grow when VFPs are allocated with + // stride 4 (more vpush instructions). But WatchOS uses a compact unwind + // format which it's more important to get right. + return isTargetWatchOS() || (isSwift() && !MF.getFunction()->optForMinSize()); } bool ARMSubtarget::useMovt(const MachineFunction &MF) const { diff --git a/lib/Target/ARM/ARMSubtarget.h b/lib/Target/ARM/ARMSubtarget.h index f95b682ba7c..66b56d10faa 100644 --- a/lib/Target/ARM/ARMSubtarget.h +++ b/lib/Target/ARM/ARMSubtarget.h @@ -212,6 +212,9 @@ protected: /// Target machine allowed unsafe FP math (such as use of NEON fp) bool UnsafeFPMath; + /// UseSjLjEH - If true, the target uses SjLj exception handling (e.g. iOS). + bool UseSjLjEH; + /// stackAlignment - The minimum alignment known to hold of the stack frame on /// entry to the function and which must be maintained by every function. unsigned stackAlignment; @@ -345,6 +348,7 @@ public: bool hasMPExtension() const { return HasMPExtension; } bool hasDSP() const { return HasDSP; } bool useNaClTrap() const { return UseNaClTrap; } + bool useSjLjEH() const { return UseSjLjEH; } bool genLongCalls() const { return GenLongCalls; } bool hasFP16() const { return HasFP16; } diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp index 75d33212ac9..9c9747fa554 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -25,12 +25,15 @@ #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCMachObjectWriter.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MachO.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/raw_ostream.h" @@ -779,6 +782,220 @@ void ARMAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, } } +namespace CU { + +/// \brief Compact unwind encoding values. +enum CompactUnwindEncodings { + UNWIND_ARM_MODE_MASK = 0x0F000000, + UNWIND_ARM_MODE_FRAME = 0x01000000, + UNWIND_ARM_MODE_FRAME_D = 0x02000000, + UNWIND_ARM_MODE_DWARF = 0x04000000, + + UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000, + + UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001, + UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002, + UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004, + + UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008, + UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010, + UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020, + UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040, + UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080, + + UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000F00, + + UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF +}; + +} // end CU namespace + +/// Generate compact unwind encoding for the function based on the CFI +/// instructions. If the CFI instructions describe a frame that cannot be +/// encoded in compact unwind, the method returns UNWIND_ARM_MODE_DWARF which +/// tells the runtime to fallback and unwind using dwarf. +uint32_t ARMAsmBackendDarwin::generateCompactUnwindEncoding( + ArrayRef Instrs) const { + DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() << "generateCU()\n"); + // Only armv7k uses CFI based unwinding. + if (Subtype != MachO::CPU_SUBTYPE_ARM_V7K) + return 0; + // No .cfi directives means no frame. + if (Instrs.empty()) + return 0; + // Start off assuming CFA is at SP+0. + int CFARegister = ARM::SP; + int CFARegisterOffset = 0; + // Mark savable registers as initially unsaved + DenseMap RegOffsets; + int FloatRegCount = 0; + // Process each .cfi directive and build up compact unwind info. + for (size_t i = 0, e = Instrs.size(); i != e; ++i) { + int Reg; + const MCCFIInstruction &Inst = Instrs[i]; + switch (Inst.getOperation()) { + case MCCFIInstruction::OpDefCfa: // DW_CFA_def_cfa + CFARegisterOffset = -Inst.getOffset(); + CFARegister = MRI.getLLVMRegNum(Inst.getRegister(), true); + break; + case MCCFIInstruction::OpDefCfaOffset: // DW_CFA_def_cfa_offset + CFARegisterOffset = -Inst.getOffset(); + break; + case MCCFIInstruction::OpDefCfaRegister: // DW_CFA_def_cfa_register + CFARegister = MRI.getLLVMRegNum(Inst.getRegister(), true); + break; + case MCCFIInstruction::OpOffset: // DW_CFA_offset + Reg = MRI.getLLVMRegNum(Inst.getRegister(), true); + if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) + RegOffsets[Reg] = Inst.getOffset(); + else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) { + RegOffsets[Reg] = Inst.getOffset(); + ++FloatRegCount; + } else { + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() << ".cfi_offset on unknown register=" + << Inst.getRegister() << "\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + break; + case MCCFIInstruction::OpRelOffset: // DW_CFA_advance_loc + // Ignore + break; + default: + // Directive not convertable to compact unwind, bail out. + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() + << "CFI directive not compatiable with comact " + "unwind encoding, opcode=" << Inst.getOperation() + << "\n"); + return CU::UNWIND_ARM_MODE_DWARF; + break; + } + } + + // If no frame set up, return no unwind info. + if ((CFARegister == ARM::SP) && (CFARegisterOffset == 0)) + return 0; + + // Verify standard frame (lr/r7) was used. + if (CFARegister != ARM::R7) { + DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() << "frame register is " + << CFARegister + << " instead of r7\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + int StackAdjust = CFARegisterOffset - 8; + if (RegOffsets.lookup(ARM::LR) != (-4 - StackAdjust)) { + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() + << "LR not saved as standard frame, StackAdjust=" + << StackAdjust + << ", CFARegisterOffset=" << CFARegisterOffset + << ", lr save at offset=" << RegOffsets[14] << "\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + if (RegOffsets.lookup(ARM::R7) != (-8 - StackAdjust)) { + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() << "r7 not saved as standard frame\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + uint32_t CompactUnwindEncoding = CU::UNWIND_ARM_MODE_FRAME; + + // If var-args are used, there may be a stack adjust required. + switch (StackAdjust) { + case 0: + break; + case 4: + CompactUnwindEncoding |= 0x00400000; + break; + case 8: + CompactUnwindEncoding |= 0x00800000; + break; + case 12: + CompactUnwindEncoding |= 0x00C00000; + break; + default: + DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() + << ".cfi_def_cfa stack adjust (" + << StackAdjust << ") out of range\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + + // If r6 is saved, it must be right below r7. + static struct { + unsigned Reg; + unsigned Encoding; + } GPRCSRegs[] = {{ARM::R6, CU::UNWIND_ARM_FRAME_FIRST_PUSH_R6}, + {ARM::R5, CU::UNWIND_ARM_FRAME_FIRST_PUSH_R5}, + {ARM::R4, CU::UNWIND_ARM_FRAME_FIRST_PUSH_R4}, + {ARM::R12, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R12}, + {ARM::R11, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R11}, + {ARM::R10, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R10}, + {ARM::R9, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R9}, + {ARM::R8, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R8}}; + + int CurOffset = -8 - StackAdjust; + for (auto CSReg : GPRCSRegs) { + auto Offset = RegOffsets.find(CSReg.Reg); + if (Offset == RegOffsets.end()) + continue; + + int RegOffset = Offset->second; + if (RegOffset != CurOffset - 4) { + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() << MRI.getName(CSReg.Reg) << " saved at " + << RegOffset << " but only supported at " + << CurOffset << "\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + CompactUnwindEncoding |= CSReg.Encoding; + CurOffset -= 4; + } + + // If no floats saved, we are done. + if (FloatRegCount == 0) + return CompactUnwindEncoding; + + // Switch mode to include D register saving. + CompactUnwindEncoding &= ~CU::UNWIND_ARM_MODE_MASK; + CompactUnwindEncoding |= CU::UNWIND_ARM_MODE_FRAME_D; + + // FIXME: supporting more than 4 saved D-registers compactly would be trivial, + // but needs coordination with the linker and libunwind. + if (FloatRegCount > 4) { + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() << "unsupported number of D registers saved (" + << FloatRegCount << ")\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + + // Floating point registers must either be saved sequentially, or we defer to + // DWARF. No gaps allowed here so check that each saved d-register is + // precisely where it should be. + static unsigned FPRCSRegs[] = { ARM::D8, ARM::D10, ARM::D12, ARM::D14 }; + for (int Idx = FloatRegCount - 1; Idx >= 0; --Idx) { + auto Offset = RegOffsets.find(FPRCSRegs[Idx]); + if (Offset == RegOffsets.end()) { + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() << FloatRegCount << " D-regs saved, but " + << MRI.getName(FPRCSRegs[Idx]) + << " not saved\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } else if (Offset->second != CurOffset - 8) { + DEBUG_WITH_TYPE("compact-unwind", + llvm::dbgs() << FloatRegCount << " D-regs saved, but " + << MRI.getName(FPRCSRegs[Idx]) + << " saved at " << Offset->second + << ", expected at " << CurOffset - 8 + << "\n"); + return CU::UNWIND_ARM_MODE_DWARF; + } + CurOffset -= 8; + } + + return CompactUnwindEncoding | ((FloatRegCount - 1) << 8); +} + static MachO::CPUSubTypeARM getMachOSubTypeFromArch(StringRef Arch) { unsigned AK = ARM::parseArch(Arch); switch (AK) { @@ -821,7 +1038,7 @@ MCAsmBackend *llvm::createARMAsmBackend(const Target &T, llvm_unreachable("unsupported object format"); case Triple::MachO: { MachO::CPUSubTypeARM CS = getMachOSubTypeFromArch(TheTriple.getArchName()); - return new ARMAsmBackendDarwin(T, TheTriple, CS); + return new ARMAsmBackendDarwin(T, TheTriple, MRI, CS); } case Triple::COFF: assert(TheTriple.isOSWindows() && "non-Windows ARM COFF is not supported"); diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h index a6206e3d958..995dd0fe08e 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h +++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h @@ -16,11 +16,12 @@ using namespace llvm; namespace { class ARMAsmBackendDarwin : public ARMAsmBackend { + const MCRegisterInfo &MRI; public: const MachO::CPUSubTypeARM Subtype; ARMAsmBackendDarwin(const Target &T, const Triple &TT, - MachO::CPUSubTypeARM st) - : ARMAsmBackend(T, TT, /* IsLittleEndian */ true), Subtype(st) { + const MCRegisterInfo &MRI, MachO::CPUSubTypeARM st) + : ARMAsmBackend(T, TT, /* IsLittleEndian */ true), MRI(MRI), Subtype(st) { HasDataInCodeSupport = true; } @@ -28,6 +29,9 @@ public: return createARMMachObjectWriter(OS, /*Is64Bit=*/false, MachO::CPU_TYPE_ARM, Subtype); } + + uint32_t generateCompactUnwindEncoding( + ArrayRef Instrs) const override; }; } diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp index 1ac08159bd3..2114fa96473 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp @@ -33,7 +33,8 @@ ARMMCAsmInfoDarwin::ARMMCAsmInfoDarwin(const Triple &TheTriple) { SupportsDebugInformation = true; // Exceptions handling - ExceptionsType = ExceptionHandling::SjLj; + ExceptionsType = TheTriple.isWatchOS() ? ExceptionHandling::DwarfCFI + : ExceptionHandling::SjLj; UseIntegratedAssembler = true; } diff --git a/test/CodeGen/ARM/cfi-alignment.ll b/test/CodeGen/ARM/cfi-alignment.ll new file mode 100644 index 00000000000..11add224265 --- /dev/null +++ b/test/CodeGen/ARM/cfi-alignment.ll @@ -0,0 +1,48 @@ +; RUN: llc -mtriple=thumbv7k-apple-watchos7.0 -o - %s | FileCheck %s + +; Since d11 doesn't get pushed with the aligned registers, its frameindex +; shouldn't be modified to say it has been. + +define void @foo() { +; CHECK-LABEL: foo: +; CHECK: push {r7, lr} +; CHECK: .cfi_offset r7, -8 +; CHECK: vpush {d11} +; CHECK: vpush {d8, d9} +; CHECK: .cfi_offset d11, -16 +; CHECK: .cfi_offset d9, -24 +; CHECK: .cfi_offset d8, -32 + call void asm sideeffect "", "~{d8},~{d9},~{d11}"() + call void @bar() + ret void +} + +define void @variadic_foo(i8, ...) { +; CHECK-LABEL: variadic_foo: +; CHECK: sub sp, #12 +; CHECK: push {r7, lr} +; CHECK: .cfi_offset r7, -20 +; CHECK: sub sp, #4 +; CHECK: vpush {d11} +; CHECK: vpush {d8, d9} +; CHECK: .cfi_offset d11, -32 +; CHECK: .cfi_offset d9, -40 +; CHECK: .cfi_offset d8, -48 + call void asm sideeffect "", "~{d8},~{d9},~{d11}"() + call void @llvm.va_start(i8* null) + call void @bar() + ret void +} + +define void @test_maintain_stack_align() { +; CHECK-LABEL: test_maintain_stack_align: +; CHECK: push {r7, lr} +; CHECK: vpush {d8, d9} +; CHECK: sub sp, #8 + call void asm sideeffect "", "~{d8},~{d9}"() + call void @bar() + ret void +} + +declare void @bar() +declare void @llvm.va_start(i8*) nounwind diff --git a/test/CodeGen/ARM/eh-resume-darwin.ll b/test/CodeGen/ARM/eh-resume-darwin.ll index 0cd49775cfb..6ac025c6f05 100644 --- a/test/CodeGen/ARM/eh-resume-darwin.ll +++ b/test/CodeGen/ARM/eh-resume-darwin.ll @@ -1,5 +1,5 @@ -; RUN: llc < %s -march=arm | FileCheck %s -target triple = "armv6-apple-macosx10.6" +; RUN: llc < %s -mtriple=armv7-apple-ios -arm-atomic-cfg-tidy=0 | FileCheck %s -check-prefix=IOS +; RUN: llc < %s -mtriple=armv7k-apple-watchos -arm-atomic-cfg-tidy=0 | FileCheck %s -check-prefix=WATCHOS declare void @func() @@ -19,4 +19,5 @@ lpad: resume { i8*, i32 } %exn } -; CHECK: __Unwind_SjLj_Resume +; IOS: __Unwind_SjLj_Resume +; WATCHOS: __Unwind_Resume diff --git a/test/CodeGen/ARM/v7k-abi-align.ll b/test/CodeGen/ARM/v7k-abi-align.ll index f666efc2db9..e9b67f22edf 100644 --- a/test/CodeGen/ARM/v7k-abi-align.ll +++ b/test/CodeGen/ARM/v7k-abi-align.ll @@ -33,6 +33,8 @@ define void @test_dpr_unwind_align() { ; CHECK: push {r5, r6, r7, lr} ; CHECK-NOT: sub sp ; CHECK: vpush {d8, d9} +; CHECK: .cfi_offset d9, -24 +; CHECK: .cfi_offset d8, -32 ; [...] ; CHECK: bl _test_i64_align ; CHECK-NOT: add sp, @@ -56,6 +58,8 @@ define void @test_dpr_unwind_align_manually() { ; CHECK: push.w {r8, r11} ; CHECK: sub sp, #4 ; CHECK: vpush {d8, d9} +; CHECK: .cfi_offset d9, -40 +; CHECK: .cfi_offset d8, -48 ; [...] ; CHECK: bl _test_i64_align ; CHECK-NOT: add sp, @@ -77,6 +81,8 @@ define void @test_dpr_unwind_align_just_cs1() { ; CHECK: push {r4, r5, r6, r7, lr} ; CHECK: sub sp, #4 ; CHECK: vpush {d8, d9} +; CHECK: .cfi_offset d9, -32 +; CHECK: .cfi_offset d8, -40 ; CHECK: sub sp, #8 ; [...] ; CHECK: bl _test_i64_align diff --git a/test/CodeGen/ARM/vfp-reg-stride.ll b/test/CodeGen/ARM/vfp-reg-stride.ll index 5484cc810b0..c5339db68e3 100644 --- a/test/CodeGen/ARM/vfp-reg-stride.ll +++ b/test/CodeGen/ARM/vfp-reg-stride.ll @@ -1,4 +1,5 @@ ; RUN: llc -mcpu=swift -mtriple=thumbv7s-apple-ios -o - %s | FileCheck %s --check-prefix=CHECK-STRIDE4 +; RUN: llc -mcpu=swift -mtriple=thumbv7k-apple-watchos -o - %s | FileCheck %s --check-prefix=CHECK-STRIDE4-WATCH ; RUN: llc -mcpu=cortex-a57 -mtriple=thumbv7-linux-gnueabihf -o - %s | FileCheck %s --check-prefix=CHECK-GENERIC define void @test_reg_stride(double %a, double %b) { @@ -6,6 +7,10 @@ define void @test_reg_stride(double %a, double %b) { ; CHECK-STRIDE4-DAG: vmov d16, r ; CHECK-STRIDE4-DAG: vmov d18, r +; CHECK-STRIDE4-WATCH-LABEL: test_reg_stride: +; CHECK-STRIDE4-WATCH-DAG: vmov.f64 d16, d +; CHECK-STRIDE4-WATCH-DAG: vmov.f64 d18, d + ; CHECK-GENERIC-LABEL: test_reg_stride: ; CHECK-GENERIC-DAG: vmov.f64 d16, {{d[01]}} ; CHECK-GENERIC-DAG: vmov.f64 d17, {{d[01]}} @@ -20,6 +25,10 @@ define void @test_stride_minsize(float %a, float %b) minsize { ; CHECK-STRIDE4: vmov d2, {{r[01]}} ; CHECK-STRIDE4: vmov d3, {{r[01]}} +; CHECK-STRIDE4-WATCH-LABEL: test_stride_minsize: +; CHECK-STRIDE4-WATCH-DAG: vmov.f32 s4, {{s[01]}} +; CHECK-STRIDE4-WATCH-DAG: vmov.f32 s8, {{s[01]}} + ; CHECK-GENERIC-LABEL: test_stride_minsize: ; CHECK-GENERIC-DAG: vmov.f32 s4, {{s[01]}} ; CHECK-GENERIC-DAG: vmov.f32 s6, {{s[01]}} diff --git a/test/MC/MachO/ARM/compact-unwind-armv7k.s b/test/MC/MachO/ARM/compact-unwind-armv7k.s new file mode 100644 index 00000000000..6e8a855cafc --- /dev/null +++ b/test/MC/MachO/ARM/compact-unwind-armv7k.s @@ -0,0 +1,124 @@ +@ RUN: llvm-mc -triple=thumbv7k-apple-watchos2.0.0 -filetype=obj -o %t < %s && llvm-objdump -unwind-info %t | FileCheck %s + +@ CHECK: Contents of __compact_unwind section: + + .syntax unified + .align 2 + .code 16 + +@ CHECK-LABEL: start: {{.*}} _test_r4_r5_r6 +@ CHECK: compact encoding: 0x01000007 + .thumb_func _test_r4_r5_r6 +_test_r4_r5_r6: + .cfi_startproc + push {r4, r5, r6, r7, lr} + add r7, sp, #12 + sub sp, #16 + .cfi_def_cfa r7, 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .cfi_offset r6, -12 + .cfi_offset r5, -16 + .cfi_offset r4, -20 + .cfi_endproc + + +@ CHECK-LABEL: start: {{.*}} _test_r4_r5_r10_r11 +@ CHECK: compact encoding: 0x01000063 + .thumb_func _test_r4_r5_r10_r11 +_test_r4_r5_r10_r11: + .cfi_startproc + push {r4, r5, r7, lr} + add r7, sp, #8 + .cfi_def_cfa r7, 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .cfi_offset r5, -12 + .cfi_offset r4, -16 + push.w {r10, r11} + .cfi_offset r11, -20 + .cfi_offset r10, -24 + .cfi_endproc + + +@ CHECK-LABEL: start: {{.*}} _test_d8 +@ CHECK: compact encoding: 0x02000000 + .thumb_func _test_d8 +_test_d8: + .cfi_startproc + push {r7, lr} + mov r7, sp + .cfi_def_cfa r7, 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + vpush {d8} + .cfi_offset d8, -16 + .cfi_endproc + + +@ CHECK-LABEL: start: {{.*}} _test_d8_d10_d12_d14 +@ CHECK: compact encoding: 0x02000300 + .thumb_func _test_d8_d10_d12_d14 +_test_d8_d10_d12_d14: + .cfi_startproc + push {r7, lr} + mov r7, sp + .cfi_def_cfa r7, 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + vpush {d14} + vpush {d12} + vpush {d10} + vpush {d8} + .cfi_offset d14, -16 + .cfi_offset d12, -24 + .cfi_offset d10, -32 + .cfi_offset d8, -40 + .cfi_endproc + +@ CHECK-LABEL: start: {{.*}} _test_varargs +@ CHECK: compact encoding: 0x01c00001 + .thumb_func _test_varargs +_test_varargs: + .cfi_startproc + sub sp, #12 + push {r4, r7, lr} + add r7, sp, #4 + .cfi_def_cfa r7, 20 + .cfi_offset lr, -16 + .cfi_offset r7, -20 + .cfi_offset r4, -24 + add.w r9, r7, #8 + mov r4, r0 + stm.w r9, {r1, r2, r3} + .cfi_endproc + +@ CHECK-LABEL: start: {{.*}} _test_missing_lr +@ CHECK: compact encoding: 0x04000000 + .thumb_func _test_missing_lr +_test_missing_lr: + .cfi_startproc + push {r7} + .cfi_def_cfa r7, 4 + .cfi_offset r7, -4 + pop {r7} + bx lr + .cfi_endproc + +@ CHECK-LABEL: start: {{.*}} _test_swapped_offsets +@ CHECK: compact encoding: 0x04000000 + .thumb_func _test_swapped_offsets +_test_swapped_offsets: + .cfi_startproc + push {r7, lr} + push {r10} + push {r4} + .cfi_def_cfa r7, 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .cfi_offset r10, -12 + .cfi_offset r4, -16 + pop {r4} + pop {r10} + pop {r7, pc} + .cfi_endproc