forked from OSchip/llvm-project
ARM: add support for WatchOS's compact unwind information.
llvm-svn: 251573
This commit is contained in:
parent
2253d1c052
commit
f8e47e4868
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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<MCCFIInstruction> 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<unsigned, int> 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");
|
||||
|
|
|
@ -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<MCCFIInstruction> Instrs) const override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]}}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue