From: Lang Hames Date: Tue, 15 Mar 2016 01:43:05 +0000 (+0000) Subject: [MachO] Add MachO alt-entry directive support. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1b640e05ba57e805ed00831771b75cd2e617f656;p=platform%2Fupstream%2Fllvm.git [MachO] Add MachO alt-entry directive support. This patch adds support for the MachO .alt_entry assembly directive, and uses it for global aliases with non-zero GEP offsets. The alt_entry flag indicates that a symbol should be layed out immediately after the preceding symbol. Conceptually it introduces an alternate entry point for a function or data structure. E.g.: safe_foo: // check preconditions for foo .alt_entry fast_foo fast_foo: // body of foo, can assume preconditions. The .alt_entry flag is also implicitly set on assembly aliases of the form: a = b + C where C is a non-zero constant, since these have the same effect as an alt_entry symbol: they introduce a label that cannot be moved relative to the preceding one. Setting the alt_entry flag on aliases of this form fixes http://llvm.org/PR25381. llvm-svn: 263521 --- diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h index 384584e..3106c8c 100644 --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -280,6 +280,10 @@ protected: /// to false. bool HasNoDeadStrip; + /// True if this target supports the MachO .alt_entry directive. Defaults to + /// false. + bool HasAltEntry; + /// Used to declare a global as being a weak symbol. Defaults to ".weak". const char *WeakDirective; @@ -498,6 +502,7 @@ public: bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; } bool hasIdentDirective() const { return HasIdentDirective; } bool hasNoDeadStrip() const { return HasNoDeadStrip; } + bool hasAltEntry() const { return HasAltEntry; } const char *getWeakDirective() const { return WeakDirective; } const char *getWeakRefDirective() const { return WeakRefDirective; } bool hasWeakDefDirective() const { return HasWeakDefDirective; } diff --git a/llvm/include/llvm/MC/MCDirectives.h b/llvm/include/llvm/MC/MCDirectives.h index 326b2a1..8c74b16 100644 --- a/llvm/include/llvm/MC/MCDirectives.h +++ b/llvm/include/llvm/MC/MCDirectives.h @@ -35,6 +35,7 @@ enum MCSymbolAttr { MCSA_Local, ///< .local (ELF) MCSA_NoDeadStrip, ///< .no_dead_strip (MachO) MCSA_SymbolResolver, ///< .symbol_resolver (MachO) + MCSA_AltEntry, ///< .alt_entry (MachO) MCSA_PrivateExtern, ///< .private_extern (MachO) MCSA_Protected, ///< .protected (ELF) MCSA_Reference, ///< .reference (MachO) diff --git a/llvm/include/llvm/MC/MCSymbolMachO.h b/llvm/include/llvm/MC/MCSymbolMachO.h index 5b0321f..260c516 100644 --- a/llvm/include/llvm/MC/MCSymbolMachO.h +++ b/llvm/include/llvm/MC/MCSymbolMachO.h @@ -33,6 +33,7 @@ class MCSymbolMachO : public MCSymbol { SF_WeakReference = 0x0040, SF_WeakDefinition = 0x0080, SF_SymbolResolver = 0x0100, + SF_AltEntry = 0x0200, // Common alignment SF_CommonAlignmentMask = 0xF0FF, @@ -88,6 +89,14 @@ public: modifyFlags(SF_SymbolResolver, SF_SymbolResolver); } + void setAltEntry() const { + modifyFlags(SF_AltEntry, SF_AltEntry); + } + + bool isAltEntry() const { + return getFlags() & SF_AltEntry; + } + void setDesc(unsigned Value) const { assert(Value == (Value & SF_DescFlagsMask) && "Invalid .desc value!"); @@ -96,7 +105,7 @@ public: /// \brief Get the encoded value of the flags as they will be emitted in to /// the MachO binary - uint16_t getEncodedFlags() const { + uint16_t getEncodedFlags(bool EncodeAsAltEntry) const { uint16_t Flags = getFlags(); // Common alignment is packed into the 'desc' bits. @@ -113,6 +122,9 @@ public: } } + if (EncodeAsAltEntry) + Flags |= SF_AltEntry; + return Flags; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 28d79315..67153d1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1165,8 +1165,13 @@ bool AsmPrinter::doFinalization(Module &M) { EmitVisibility(Name, Alias.getVisibility()); + const MCExpr *Expr = lowerConstant(Alias.getAliasee()); + + if (MAI->hasAltEntry() && isa(Expr)) + OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry); + // Emit the directives as assignments aka .set: - OutStreamer->EmitAssignment(Name, lowerConstant(Alias.getAliasee())); + OutStreamer->EmitAssignment(Name, Expr); // If the aliasee does not correspond to a symbol in the output, i.e. the // alias is not of an object or the aliased object is private, then set the diff --git a/llvm/lib/MC/MCAsmInfo.cpp b/llvm/lib/MC/MCAsmInfo.cpp index 36e10b3..fa7d438 100644 --- a/llvm/lib/MC/MCAsmInfo.cpp +++ b/llvm/lib/MC/MCAsmInfo.cpp @@ -75,6 +75,7 @@ MCAsmInfo::MCAsmInfo() { HasSingleParameterDotFile = true; HasIdentDirective = false; HasNoDeadStrip = false; + HasAltEntry = false; WeakDirective = "\t.weak\t"; WeakRefDirective = nullptr; HasWeakDefDirective = false; diff --git a/llvm/lib/MC/MCAsmInfoDarwin.cpp b/llvm/lib/MC/MCAsmInfoDarwin.cpp index ae9486d..dff5dd0 100644 --- a/llvm/lib/MC/MCAsmInfoDarwin.cpp +++ b/llvm/lib/MC/MCAsmInfoDarwin.cpp @@ -88,6 +88,7 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { HasDotTypeDotSizeDirective = false; HasNoDeadStrip = true; + HasAltEntry = true; DwarfUsesRelocationsAcrossSections = false; diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index c615752..be26449 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -472,6 +472,7 @@ bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, OS << "\t.no_dead_strip\t"; break; case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break; + case MCSA_AltEntry: OS << "\t.alt_entry\t"; break; case MCSA_PrivateExtern: OS << "\t.private_extern\t"; break; diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp index eebdc9b..9249d9c 100644 --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -283,6 +283,9 @@ bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { case MCSA_Internal: Symbol->setVisibility(ELF::STV_INTERNAL); break; + + case MCSA_AltEntry: + llvm_unreachable("ELF doesn't support this attribute"); } return true; diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index f59fa1d..a725163 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -23,6 +23,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSymbolMachO.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" @@ -70,6 +71,7 @@ public: void ChangeSection(MCSection *Sect, const MCExpr *Subsect) override; void EmitLabel(MCSymbol *Symbol) override; + void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; void EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) override; void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitLinkerOptions(ArrayRef Options) override; @@ -198,6 +200,16 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { cast(Symbol)->clearReferenceType(); } +void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + MCValue Res; + + if (Value->evaluateAsRelocatable(Res, nullptr, nullptr)) + if (Res.getSymA() && !Res.getSymB() && Res.getConstant() != 0) + cast(Symbol)->setAltEntry(); + + MCObjectStreamer::EmitAssignment(Symbol, Value); +} + void MCMachOStreamer::EmitDataRegion(DataRegionData::KindTy Kind) { if (!getAssembler().getBackend().hasDataInCodeSupport()) return; @@ -346,6 +358,10 @@ bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym, Symbol->setSymbolResolver(); break; + case MCSA_AltEntry: + Symbol->setAltEntry(); + break; + case MCSA_PrivateExtern: Symbol->setExternal(true); Symbol->setPrivateExtern(true); diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index b962d9f..fef6bb6 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -350,8 +350,8 @@ private: DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR, DK_BUNDLE_ALIGN_MODE, DK_BUNDLE_LOCK, DK_BUNDLE_UNLOCK, DK_ZERO, DK_EXTERN, DK_GLOBL, DK_GLOBAL, - DK_LAZY_REFERENCE, DK_NO_DEAD_STRIP, DK_SYMBOL_RESOLVER, DK_PRIVATE_EXTERN, - DK_REFERENCE, DK_WEAK_DEFINITION, DK_WEAK_REFERENCE, + DK_LAZY_REFERENCE, DK_NO_DEAD_STRIP, DK_SYMBOL_RESOLVER, DK_ALT_ENTRY, + DK_PRIVATE_EXTERN, DK_REFERENCE, DK_WEAK_DEFINITION, DK_WEAK_REFERENCE, DK_WEAK_DEF_CAN_BE_HIDDEN, DK_COMM, DK_COMMON, DK_LCOMM, DK_ABORT, DK_INCLUDE, DK_INCBIN, DK_CODE16, DK_CODE16GCC, DK_REPT, DK_IRP, DK_IRPC, DK_IF, DK_IFEQ, DK_IFGE, DK_IFGT, DK_IFLE, DK_IFLT, DK_IFNE, DK_IFB, @@ -1598,6 +1598,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip); case DK_SYMBOL_RESOLVER: return parseDirectiveSymbolAttribute(MCSA_SymbolResolver); + case DK_ALT_ENTRY: + return parseDirectiveSymbolAttribute(MCSA_AltEntry); case DK_PRIVATE_EXTERN: return parseDirectiveSymbolAttribute(MCSA_PrivateExtern); case DK_REFERENCE: @@ -4625,6 +4627,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE; DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP; DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER; + DirectiveKindMap[".alt_entry"] = DK_ALT_ENTRY; DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN; DirectiveKindMap[".reference"] = DK_REFERENCE; DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION; diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp index 8ebd703..2013c25 100644 --- a/llvm/lib/MC/MachObjectWriter.cpp +++ b/llvm/lib/MC/MachObjectWriter.cpp @@ -334,7 +334,7 @@ void MachObjectWriter::writeNlist(MachSymbolData &MSD, if (AliaseeInfo) SectionIndex = AliaseeInfo->SectionIndex; Symbol = AliasedSymbol; - // FIXME: Should this update Data as well? Do we need OrigSymbol at all? + // FIXME: Should this update Data as well? } // Set the N_TYPE bits. See . @@ -377,7 +377,9 @@ void MachObjectWriter::writeNlist(MachSymbolData &MSD, // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. - write16(cast(Symbol)->getEncodedFlags()); + bool EncodeAsAltEntry = + IsAlias && cast(OrigSymbol).isAltEntry(); + write16(cast(Symbol)->getEncodedFlags(EncodeAsAltEntry)); if (is64Bit()) write64(Address); else diff --git a/llvm/test/CodeGen/X86/alias-gep.ll b/llvm/test/CodeGen/X86/alias-gep.ll new file mode 100644 index 0000000..5ecf20b --- /dev/null +++ b/llvm/test/CodeGen/X86/alias-gep.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck --check-prefix=MACHO %s +; RUN: llc < %s -mtriple=x86_64-pc-linux | FileCheck --check-prefix=ELF %s + +;MACHO: .globl _offsetSym0 +;MACHO-NOT: .alt_entry +;MACHO: _offsetSym0 = _s +;MACHO: .globl _offsetSym1 +;MACHO: .alt_entry _offsetSym1 +;MACHO: _offsetSym1 = _s+8 + +;ELF: .globl offsetSym0 +;ELF-NOT: .alt_entry +;ELF: offsetSym0 = s +;ELF: .globl offsetSym1 +;ELF-NOT: .alt_entry +;ELF: offsetSym1 = s+8 + +%struct.S1 = type { i32, i32, i32 } + +@s = global %struct.S1 { i32 31, i32 32, i32 33 }, align 4 +@offsetSym0 = alias i32, i32* getelementptr inbounds (%struct.S1, %struct.S1* @s, i64 0, i32 0) +@offsetSym1 = alias i32, i32* getelementptr inbounds (%struct.S1, %struct.S1* @s, i64 0, i32 2) diff --git a/llvm/test/MC/MachO/absolute.s b/llvm/test/MC/MachO/absolute.s index 36a0ae5..26850a2 100644 --- a/llvm/test/MC/MachO/absolute.s +++ b/llvm/test/MC/MachO/absolute.s @@ -79,7 +79,8 @@ foo_equals2 = (_foo - _bar + 0xffff0000) // CHECK: Type: Section (0xE) // CHECK: Section: __text (0x1) // CHECK: RefType: UndefinedNonLazy (0x0) -// CHECK: Flags [ (0x20) +// CHECK: Flags [ (0x220) +// CHECK: AltEntry (0x200) // CHECK: NoDeadStrip (0x20) // CHECK: ] // CHECK: Value: 0xFFFF0001 @@ -99,7 +100,8 @@ foo_equals2 = (_foo - _bar + 0xffff0000) // CHECK: Type: Section (0xE) // CHECK: Section: __text (0x1) // CHECK: RefType: UndefinedNonLazy (0x0) -// CHECK: Flags [ (0x0) +// CHECK: Flags [ (0x200) +// CHECK: AltEntry (0x200) // CHECK: ] // CHECK: Value: 0xFFFF0001 // CHECK: } @@ -118,7 +120,8 @@ foo_equals2 = (_foo - _bar + 0xffff0000) // CHECK: Type: Section (0xE) // CHECK: Section: __text (0x1) // CHECK: RefType: UndefinedNonLazy (0x0) -// CHECK: Flags [ (0x20) +// CHECK: Flags [ (0x220) +// CHECK: AltEntry (0x200) // CHECK: NoDeadStrip (0x20) // CHECK: ] // CHECK: Value: 0xFFFF0001 diff --git a/llvm/test/MC/MachO/altentry.s b/llvm/test/MC/MachO/altentry.s new file mode 100644 index 0000000..73cc261 --- /dev/null +++ b/llvm/test/MC/MachO/altentry.s @@ -0,0 +1,55 @@ +// RUN: llvm-mc -triple x86_64-apple-darwin -filetype=obj %s -o - | llvm-readobj -t | FileCheck %s + + // CHECK: Symbol { + // CHECK: Name: _offsetsym0 + // CHECK: Flags [ (0x0) + // CHECK: Value: 0x0 + + // CHECK: Symbol { + // CHECK: Name: _offsetsym1 + // CHECK: Flags [ (0x200) + // CHECK: Value: 0x4 + + // CHECK: Symbol { + // CHECK: Name: _offsetsym2 + // CHECK: Flags [ (0x200) + // CHECK: Value: 0x8 + + // CHECK: Symbol { + // CHECK: Name: _offsetsym3 + // CHECK: Flags [ (0x200) + // CHECK: Value: 0x18 + + // CHECK: Symbol { + // CHECK: Symbol { + // CHECK: Symbol { + + .section __TEXT,__text,regular,pure_instructions + .comm _g0,4,2 + .section __DATA,__data + .globl _s0 + .align 3 +_s0: + .long 31 + .long 32 + .quad _g0 + + .globl _s1 + .align 3 +_s1: + .long 33 + .long 34 + .quad _g0 + + .globl _offsetsym0 + _offsetsym0 = _s0 + .globl _offsetsym1 + .alt_entry _offsetsym1 + _offsetsym1 = _s0+4 + .globl _offsetsym2 + .alt_entry _offsetsym2 + _offsetsym2 = _s0+8 + .globl _offsetsym3 + .alt_entry _offsetsym3 + _offsetsym3 = _s1+8 + .subsections_via_symbols diff --git a/llvm/test/MC/MachO/variable-exprs.s b/llvm/test/MC/MachO/variable-exprs.s index 85f395f..5369622 100644 --- a/llvm/test/MC/MachO/variable-exprs.s +++ b/llvm/test/MC/MachO/variable-exprs.s @@ -151,7 +151,7 @@ Lt0_x = Lt0_a - Lt0_b // CHECK-I386: Type: Section (0xE) // CHECK-I386: Section: __data (0x2) // CHECK-I386: RefType: UndefinedNonLazy (0x0) -// CHECK-I386: Flags [ (0x0) +// CHECK-I386: Flags [ (0x200) // CHECK-I386: ] // CHECK-I386: Value: 0x9 // CHECK-I386: } @@ -208,7 +208,7 @@ Lt0_x = Lt0_a - Lt0_b // CHECK-I386: Type: Undef (0x0) // CHECK-I386: Section: (0x0) // CHECK-I386: RefType: UndefinedNonLazy (0x0) -// CHECK-I386: Flags [ (0x0) +// CHECK-I386: Flags [ (0x200) // CHECK-I386: ] // CHECK-I386: Value: 0x0 // CHECK-I386: } @@ -360,7 +360,7 @@ Lt0_x = Lt0_a - Lt0_b // CHECK-X86_64: Type: Section (0xE) // CHECK-X86_64: Section: __data (0x2) // CHECK-X86_64: RefType: UndefinedNonLazy (0x0) -// CHECK-X86_64: Flags [ (0x0) +// CHECK-X86_64: Flags [ (0x200) // CHECK-X86_64: ] // CHECK-X86_64: Value: 0x9 // CHECK-X86_64: } @@ -417,7 +417,7 @@ Lt0_x = Lt0_a - Lt0_b // CHECK-X86_64: Type: Undef (0x0) // CHECK-X86_64: Section: (0x0) // CHECK-X86_64: RefType: UndefinedNonLazy (0x0) -// CHECK-X86_64: Flags [ (0x0) +// CHECK-X86_64: Flags [ (0x200) // CHECK-X86_64: ] // CHECK-X86_64: Value: 0x0 // CHECK-X86_64: } diff --git a/llvm/test/MC/MachO/x86_64-reloc-arithmetic.s b/llvm/test/MC/MachO/x86_64-reloc-arithmetic.s index de52479..bce9dbd 100644 --- a/llvm/test/MC/MachO/x86_64-reloc-arithmetic.s +++ b/llvm/test/MC/MachO/x86_64-reloc-arithmetic.s @@ -31,7 +31,8 @@ _baz: // CHECK-NEXT: Type: Section (0xE) // CHECK-NEXT: Section: __text (0x1) // CHECK-NEXT: RefType: UndefinedNonLazy (0x0) -// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: Flags [ (0x200) +// CHECK-NEXT: AltEntry (0x200) // CHECK-NEXT: ] // CHECK-NEXT: Value: 0x102 // CHECK-NEXT: } diff --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp index 58d2c9f..8bd09b6 100644 --- a/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/llvm/tools/llvm-readobj/MachODumper.cpp @@ -239,7 +239,8 @@ static const EnumEntry MachOSymbolFlags[] = { { "ReferencedDynamically", 0x10 }, { "NoDeadStrip", 0x20 }, { "WeakRef", 0x40 }, - { "WeakDef", 0x80 } + { "WeakDef", 0x80 }, + { "AltEntry", 0x200 }, }; static const EnumEntry MachOSymbolTypes[] = {