diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -41,6 +41,7 @@ class DwarfDebug; class GCMetadataPrinter; class GCStrategy; +class GlobalAlias; class GlobalObject; class GlobalValue; class GlobalVariable; @@ -474,7 +475,11 @@ virtual const MCExpr *lowerConstant(const Constant *CV); /// Print a general LLVM constant to the .s file. - void emitGlobalConstant(const DataLayout &DL, const Constant *CV); + /// On AIX, when an alias refers to a sub-element of a global variable, the + /// label of that alias needs to be emitted before the corresponding element. + using AliasMapTy = DenseMap>; + void emitGlobalConstant(const DataLayout &DL, const Constant *CV, + AliasMapTy *AliasList = nullptr); /// Unnamed constant global variables solely contaning a pointer to /// another globals variable act like a global variable "proxy", or GOT diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1816,6 +1816,11 @@ if (TM.getTargetTriple().isOSBinFormatXCOFF()) { assert(MAI->hasVisibilityOnlyWithLinkage() && "Visibility should be handled with emitLinkage() on AIX."); + + // Linkage for alias of global variable has been emitted. + if (isa(GA.getAliaseeObject())) + return; + emitLinkage(&GA, Name); // If it's a function, also emit linkage for aliases of function entry // point. @@ -2874,7 +2879,8 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *C, AsmPrinter &AP, const Constant *BaseCV = nullptr, - uint64_t Offset = 0); + uint64_t Offset = 0, + AsmPrinter::AliasMapTy *AliasList = nullptr); static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP); static void emitGlobalConstantFP(APFloat APF, Type *ET, AsmPrinter &AP); @@ -2928,9 +2934,21 @@ return -1; } -static void emitGlobalConstantDataSequential(const DataLayout &DL, - const ConstantDataSequential *CDS, - AsmPrinter &AP) { +static void emitGlobalAliasInline(AsmPrinter &AP, uint64_t Offset, + AsmPrinter::AliasMapTy *AliasList) { + if (AliasList) { + auto AliasIt = AliasList->find(Offset); + if (AliasIt != AliasList->end()) { + for (const GlobalAlias *GA : AliasIt->second) + AP.OutStreamer->emitLabel(AP.getSymbol(GA)); + AliasList->erase(Offset); + } + } +} + +static void emitGlobalConstantDataSequential( + const DataLayout &DL, const ConstantDataSequential *CDS, AsmPrinter &AP, + AsmPrinter::AliasMapTy *AliasList) { // See if we can aggregate this into a .fill, if so, emit it as such. int Value = isRepeatedByteSequence(CDS, DL); if (Value != -1) { @@ -2947,17 +2965,20 @@ // Otherwise, emit the values in successive locations. unsigned ElementByteSize = CDS->getElementByteSize(); if (isa(CDS->getElementType())) { - for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { + for (unsigned I = 0, E = CDS->getNumElements(); I != E; ++I) { + emitGlobalAliasInline(AP, ElementByteSize * I, AliasList); if (AP.isVerbose()) AP.OutStreamer->getCommentOS() - << format("0x%" PRIx64 "\n", CDS->getElementAsInteger(i)); - AP.OutStreamer->emitIntValue(CDS->getElementAsInteger(i), + << format("0x%" PRIx64 "\n", CDS->getElementAsInteger(I)); + AP.OutStreamer->emitIntValue(CDS->getElementAsInteger(I), ElementByteSize); } } else { Type *ET = CDS->getElementType(); - for (unsigned I = 0, E = CDS->getNumElements(); I != E; ++I) + for (unsigned I = 0, E = CDS->getNumElements(); I != E; ++I) { + emitGlobalAliasInline(AP, ElementByteSize * I, AliasList); emitGlobalConstantFP(CDS->getElementAsAPFloat(I), ET, AP); + } } unsigned Size = DL.getTypeAllocSize(CDS->getType()); @@ -2970,7 +2991,8 @@ static void emitGlobalConstantArray(const DataLayout &DL, const ConstantArray *CA, AsmPrinter &AP, - const Constant *BaseCV, uint64_t Offset) { + const Constant *BaseCV, uint64_t Offset, + AsmPrinter::AliasMapTy *AliasList) { // See if we can aggregate some values. Make sure it can be // represented as a series of bytes of the constant value. int Value = isRepeatedByteSequence(CA, DL); @@ -2978,19 +3000,22 @@ if (Value != -1) { uint64_t Bytes = DL.getTypeAllocSize(CA->getType()); AP.OutStreamer->emitFill(Bytes, Value); - } - else { - for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { - emitGlobalConstantImpl(DL, CA->getOperand(i), AP, BaseCV, Offset); - Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType()); + } else { + for (unsigned I = 0, E = CA->getNumOperands(); I != E; ++I) { + emitGlobalConstantImpl(DL, CA->getOperand(I), AP, BaseCV, Offset, + AliasList); + Offset += DL.getTypeAllocSize(CA->getOperand(I)->getType()); } } } static void emitGlobalConstantVector(const DataLayout &DL, - const ConstantVector *CV, AsmPrinter &AP) { - for (unsigned i = 0, e = CV->getType()->getNumElements(); i != e; ++i) - emitGlobalConstantImpl(DL, CV->getOperand(i), AP); + const ConstantVector *CV, AsmPrinter &AP, + AsmPrinter::AliasMapTy *AliasList) { + for (unsigned I = 0, E = CV->getType()->getNumElements(); I != E; ++I) { + emitGlobalAliasInline(AP, DL.getTypeAllocSize(CV->getType()) * I, AliasList); + emitGlobalConstantImpl(DL, CV->getOperand(I), AP); + } unsigned Size = DL.getTypeAllocSize(CV->getType()); unsigned EmittedSize = DL.getTypeAllocSize(CV->getType()->getElementType()) * @@ -3001,21 +3026,24 @@ static void emitGlobalConstantStruct(const DataLayout &DL, const ConstantStruct *CS, AsmPrinter &AP, - const Constant *BaseCV, uint64_t Offset) { + const Constant *BaseCV, uint64_t Offset, + AsmPrinter::AliasMapTy *AliasList) { // Print the fields in successive locations. Pad to align if needed! unsigned Size = DL.getTypeAllocSize(CS->getType()); const StructLayout *Layout = DL.getStructLayout(CS->getType()); uint64_t SizeSoFar = 0; - for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { - const Constant *Field = CS->getOperand(i); + for (unsigned I = 0, E = CS->getNumOperands(); I != E; ++I) { + const Constant *Field = CS->getOperand(I); // Print the actual field value. - emitGlobalConstantImpl(DL, Field, AP, BaseCV, Offset + SizeSoFar); + emitGlobalConstantImpl(DL, Field, AP, BaseCV, Offset + SizeSoFar, + AliasList); // Check if padding is needed and insert one or more 0s. uint64_t FieldSize = DL.getTypeAllocSize(Field->getType()); - uint64_t PadSize = ((i == e-1 ? Size : Layout->getElementOffset(i+1)) - - Layout->getElementOffset(i)) - FieldSize; + uint64_t PadSize = ((I == E - 1 ? Size : Layout->getElementOffset(I + 1)) - + Layout->getElementOffset(I)) - + FieldSize; SizeSoFar += FieldSize + PadSize; // Insert padding - this may include padding to increase the size of the @@ -3225,7 +3253,9 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV, AsmPrinter &AP, const Constant *BaseCV, - uint64_t Offset) { + uint64_t Offset, + AsmPrinter::AliasMapTy *AliasList) { + emitGlobalAliasInline(AP, Offset, AliasList); uint64_t Size = DL.getTypeAllocSize(CV->getType()); // Globals with sub-elements such as combinations of arrays and structs @@ -3265,13 +3295,13 @@ } if (const ConstantDataSequential *CDS = dyn_cast(CV)) - return emitGlobalConstantDataSequential(DL, CDS, AP); + return emitGlobalConstantDataSequential(DL, CDS, AP, AliasList); if (const ConstantArray *CVA = dyn_cast(CV)) - return emitGlobalConstantArray(DL, CVA, AP, BaseCV, Offset); + return emitGlobalConstantArray(DL, CVA, AP, BaseCV, Offset, AliasList); if (const ConstantStruct *CVS = dyn_cast(CV)) - return emitGlobalConstantStruct(DL, CVS, AP, BaseCV, Offset); + return emitGlobalConstantStruct(DL, CVS, AP, BaseCV, Offset, AliasList); if (const ConstantExpr *CE = dyn_cast(CV)) { // Look through bitcasts, which might not be able to be MCExpr'ized (e.g. of @@ -3290,7 +3320,7 @@ } if (const ConstantVector *V = dyn_cast(CV)) - return emitGlobalConstantVector(DL, V, AP); + return emitGlobalConstantVector(DL, V, AP, AliasList); // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. @@ -3306,10 +3336,11 @@ } /// EmitGlobalConstant - Print a general LLVM constant to the .s file. -void AsmPrinter::emitGlobalConstant(const DataLayout &DL, const Constant *CV) { +void AsmPrinter::emitGlobalConstant(const DataLayout &DL, const Constant *CV, + AliasMapTy *AliasList) { uint64_t Size = DL.getTypeAllocSize(CV->getType()); if (Size) - emitGlobalConstantImpl(DL, CV, *this); + emitGlobalConstantImpl(DL, CV, *this, nullptr, 0, AliasList); else if (MAI->hasSubsectionsViaSymbols()) { // If the global has zero size, emit a single byte so that two labels don't // look like they are at the same location. diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -230,6 +230,9 @@ void emitGlobalVariableHelper(const GlobalVariable *); + // Get the offset of an alias based on its AliaseeObject. + uint64_t getAliasOffset(const Constant *C); + public: PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) : PPCAsmPrinter(TM, std::move(Streamer)) { @@ -2352,6 +2355,24 @@ .Default(false); } +uint64_t PPCAIXAsmPrinter::getAliasOffset(const Constant *C) { + if (auto *GA = dyn_cast(C)) + return getAliasOffset(GA->getAliasee()); + if (auto *CE = dyn_cast(C)) { + const MCExpr *LowC = lowerConstant(CE); + const MCBinaryExpr *CBE = dyn_cast(LowC); + if (!CBE) + return 0; + if (CBE->getOpcode() != MCBinaryExpr::Add) + report_fatal_error("Only adding an offset is supported now."); + auto *RHS = dyn_cast(CBE->getRHS()); + if (!RHS) + report_fatal_error("Unable to get the offset of alias."); + return RHS->getValue(); + } + return 0; +} + void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { // Special LLVM global arrays have been handled at the initialization. if (isSpecialLLVMGlobalArrayToSkip(GV) || isSpecialLLVMGlobalArrayForStaticInit(GV)) @@ -2422,20 +2443,34 @@ } MCSymbol *EmittedInitSym = GVSym; + + // Emit linkage for the global variable and its aliases. emitLinkage(GV, EmittedInitSym); + for (const GlobalAlias *GA : GOAliasMap[GV]) + emitLinkage(GA, getSymbol(GA)); + emitAlignment(getGVAlignment(GV, DL), GV); // When -fdata-sections is enabled, every GlobalVariable will // be put into its own csect; therefore, label is not necessary here. - if (!TM.getDataSections() || GV->hasSection()) { + if (!TM.getDataSections() || GV->hasSection()) OutStreamer->emitLabel(EmittedInitSym); + + // No alias to emit. + if (!GOAliasMap[GV].size()) { + emitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); + return; } - // Emit aliasing label for global variable. - for (const GlobalAlias *Alias : GOAliasMap[GV]) - OutStreamer->emitLabel(getSymbol(Alias)); + // Aliases with the same offset should be aligned. Record the list of aliases + // associated with the offset. + AliasMapTy AliasList; + for (const GlobalAlias *GA : GOAliasMap[GV]) + AliasList[getAliasOffset(GA->getAliasee())].push_back(GA); - emitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); + // Emit alias label and element value for global variable. + emitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer(), + &AliasList); } void PPCAIXAsmPrinter::emitFunctionDescriptor() { diff --git a/llvm/test/CodeGen/PowerPC/aix-alias-alignment-2.ll b/llvm/test/CodeGen/PowerPC/aix-alias-alignment-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-alias-alignment-2.ll @@ -0,0 +1,79 @@ +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -data-sections=false < %s | FileCheck --check-prefix=ASM %s + +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -data-sections=false -filetype=obj -o %t.o < %s +; RUN: llvm-objdump --syms %t.o | FileCheck --check-prefix=SYM %s + +@ConstVector = global <2 x i64> , align 4 +@var1 = alias i64, getelementptr inbounds (<2 x i64>, <2 x i64>* @ConstVector, i32 0, i32 1) +define void @foo1(i64 %a1) { + store i64 %a1, i64* getelementptr inbounds (<2 x i64>, <2 x i64>* @ConstVector, i32 0, i32 1), align 4 + ret void +} + +; ASM: .globl ConstVector # @ConstVector +; ASM-NEXT: .globl var1 +; ASM-NEXT: .align 4 +; ASM-NEXT: ConstVector: +; ASM-NEXT: .vbyte 4, 0 # 0xc +; ASM-NEXT: .vbyte 4, 12 +; ASM-NEXT: var1: +; ASM-NEXT: .vbyte 4, 0 # 0x22 +; ASM-NEXT: .vbyte 4, 34 + +@ConstDataSeq = global [2 x i64] [i64 12, i64 34], align 4 +@var2 = alias i64, getelementptr inbounds ([2 x i64], [2 x i64]* @ConstDataSeq, i32 0, i32 1) +define void @foo2(i64 %a1) { + store i64 %a1, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @ConstDataSeq, i32 0, i32 1), align 4 + ret void +} + +; ASM: .globl ConstDataSeq # @ConstDataSeq +; ASM-NEXT: .globl var2 +; ASM-NEXT: .align 3 +; ASM-NEXT: ConstDataSeq: +; ASM-NEXT: .vbyte 4, 0 # 0xc +; ASM-NEXT: .vbyte 4, 12 +; ASM-NEXT: var2: +; ASM-NEXT: .vbyte 4, 0 # 0x22 +; ASM-NEXT: .vbyte 4, 34 + +%struct.B = type { i64 } +@ConstArray = global [2 x %struct.B] [%struct.B {i64 12}, %struct.B {i64 34}], align 4 +@var3 = alias %struct.B, getelementptr inbounds ([2 x %struct.B], [2 x %struct.B]* @ConstArray, i32 0, i32 0) +define void @foo3(%struct.B %a1) { + store %struct.B %a1, %struct.B* getelementptr inbounds ([2 x %struct.B], [2 x %struct.B]* @ConstArray, i32 0, i32 1), align 4 + ret void +} + +; ASM: .globl ConstArray # @ConstArray +; ASM-NEXT: .globl var3 +; ASM-NEXT: .align 3 +; ASM-NEXT: ConstArray: +; ASM-NEXT: var3: +; ASM-NEXT: .vbyte 4, 0 # 0xc +; ASM-NEXT: .vbyte 4, 12 +; ASM-NEXT: .vbyte 4, 0 # 0x22 +; ASM-NEXT: .vbyte 4, 34 + +; SYM: SYMBOL TABLE: +; SYM-NEXT: 00000000 df *DEBUG* 00000000 +; SYM-NEXT: 00000000 l .text 0000008a .text +; SYM-NEXT: 00000000 g F .text (csect: .text) 00000000 .foo1 +; SYM-NEXT: 00000030 g F .text (csect: .text) 00000000 .foo2 +; SYM-NEXT: 00000060 g F .text (csect: .text) 00000000 .foo3 +; SYM-NEXT: 00000090 l .data 00000030 .data +; SYM-NEXT: 00000090 g O .data (csect: .data) 00000000 ConstVector +; SYM-NEXT: 00000098 g O .data (csect: .data) 00000000 var1 +; SYM-NEXT: 000000a0 g O .data (csect: .data) 00000000 ConstDataSeq +; SYM-NEXT: 000000a8 g O .data (csect: .data) 00000000 var2 +; SYM-NEXT: 000000b0 g O .data (csect: .data) 00000000 ConstArray +; SYM-NEXT: 000000b0 g O .data (csect: .data) 00000000 var3 +; SYM-NEXT: 000000c0 g O .data 0000000c foo1 +; SYM-NEXT: 000000cc g O .data 0000000c foo2 +; SYM-NEXT: 000000d8 g O .data 0000000c foo3 +; SYM-NEXT: 000000e4 l .data 00000000 TOC +; SYM-NEXT: 000000e4 l O .data 00000004 ConstVector +; SYM-NEXT: 000000e8 l O .data 00000004 ConstDataSeq +; SYM-NEXT: 000000ec l O .data 00000004 ConstArray diff --git a/llvm/test/CodeGen/PowerPC/aix-alias-alignment.ll b/llvm/test/CodeGen/PowerPC/aix-alias-alignment.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-alias-alignment.ll @@ -0,0 +1,74 @@ +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -data-sections=false < %s | FileCheck --check-prefix=ASM %s + +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -data-sections=true < %s | FileCheck --check-prefix=ASM-DATASECT %s + +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -data-sections=false -filetype=obj -o %t.o < %s +; RUN: llvm-objdump -dr %t.o | FileCheck --check-prefix=OBJ %s +; RUN: llvm-objdump --syms %t.o | FileCheck --check-prefix=SYM %s + +@_MergedGlobals = global <{ i32, i32 }> <{ i32 1, i32 2 }>, align 4 +@var1 = alias i32, getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 0) +@var2 = alias i32, getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 1) +@var3 = alias i32, i32* @var2 + +define void @foo(i32 %a1, i32 %a2, i32 %a3) { + store i32 %a1, i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 0), align 4 + store i32 %a2, i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 1), align 4 + ret void +} + +; ASM: # -- End function +; ASM-NEXT: .csect .data[RW],2 +; ASM-NEXT: .globl _MergedGlobals # @_MergedGlobals +; ASM-NEXT: .globl var1 +; ASM-NEXT: .globl var2 +; ASM-NEXT: .globl var3 +; ASM-NEXT: .align 2 +; ASM-NEXT: _MergedGlobals: +; ASM-NEXT: var1: +; ASM-NEXT: .vbyte 4, 1 # 0x1 +; ASM-NEXT: var2: +; ASM-NEXT: var3: +; ASM-NEXT: .vbyte 4, 2 # 0x2 +; ASM-NEXT: .toc +; ASM-NEXT: L..C0: +; ASM-NEXT: .tc _MergedGlobals[TC],_MergedGlobals + +; ASM-DATASECT: # -- End function +; ASM-DATASECT-NEXT: .csect _MergedGlobals[RW],2 +; ASM-DATASECT-NEXT: .globl _MergedGlobals[RW] # @_MergedGlobals +; ASM-DATASECT-NEXT: .globl var1 +; ASM-DATASECT-NEXT: .globl var2 +; ASM-DATASECT-NEXT: .globl var3 +; ASM-DATASECT-NEXT: .align 2 +; ASM-DATASECT-NEXT: var1: +; ASM-DATASECT-NEXT: .vbyte 4, 1 # 0x1 +; ASM-DATASECT-NEXT: var2: +; ASM-DATASECT-NEXT: var3: +; ASM-DATASECT-NEXT: .vbyte 4, 2 # 0x2 +; ASM-DATASECT-NEXT: .toc +; ASM-DATASECT-NEXT: L..C0: +; ASM-DATASECT-NEXT: .tc _MergedGlobals[TC],_MergedGlobals[RW] + +; OBJ: 00000000 <.foo>: +; OBJ-NEXT: 0: 80 a2 00 00 lwz 5, 0(2) +; OBJ-NEXT: 00000002: R_TOC _MergedGlobals +; OBJ-NEXT: 4: 90 65 00 00 stw 3, 0(5) +; OBJ-NEXT: 8: 90 85 00 04 stw 4, 4(5) +; OBJ-NEXT: c: 4e 80 00 20 blr + +; SYM: SYMBOL TABLE: +; SYM-NEXT: 00000000 df *DEBUG* 00000000 +; SYM-NEXT: 00000000 l .text 00000029 .text +; SYM-NEXT: 00000000 g F .text (csect: .text) 00000000 .foo +; SYM-NEXT: 0000002c l .data 00000008 .data +; SYM-NEXT: 0000002c g O .data (csect: .data) 00000000 _MergedGlobals +; SYM-NEXT: 0000002c g O .data (csect: .data) 00000000 var1 +; SYM-NEXT: 00000030 g O .data (csect: .data) 00000000 var2 +; SYM-NEXT: 00000030 g O .data (csect: .data) 00000000 var3 +; SYM-NEXT: 00000034 g O .data 0000000c foo +; SYM-NEXT: 00000040 l .data 00000000 TOC +; SYM-NEXT: 00000040 l O .data 00000004 _MergedGlobals diff --git a/llvm/test/CodeGen/PowerPC/aix-alias.ll b/llvm/test/CodeGen/PowerPC/aix-alias.ll --- a/llvm/test/CodeGen/PowerPC/aix-alias.ll +++ b/llvm/test/CodeGen/PowerPC/aix-alias.ll @@ -75,6 +75,12 @@ ; ASM: # -- End function ; ASM-NEXT: .csect .data[RW] ; ASM-NEXT: .globl var +; ASM-NEXT: .globl var1 +; ASM-NEXT: .globl var2 +; ASM-NEXT: .weak var_l +; ASM-NEXT: .lglobl var_i +; ASM-NEXT: .globl var_h,hidden +; ASM-NEXT: .globl var_p,protected ; ASM: var: ; ASM-NEXT: var1: ; ASM-NEXT: var2: @@ -83,24 +89,18 @@ ; ASM-NEXT: var_h: ; ASM-NEXT: var_p: ; ASM-NEXT: .vbyte 4, 42 -; ASM-NEXT: .globl array +; ASM-NEXT: .globl array ; ASM: array: ; ASM-NEXT: .vbyte 4, 1 # 0x1 ; ASM-NEXT: .vbyte 4, 2 # 0x2 ; ASM-NEXT: .globl x +; ASM-NEXT: .globl bitcast_alias ; ASM: x: ; ASM-NEXT: bitcast_alias: ; ASM-NEXT: .vbyte {{[0-9]+}}, array+4 ; ASM-NEXT: .globl fun_ptr ; ASM: fun_ptr: ; ASM-NEXT: .vbyte {{[0-9]+}}, fun_weak -; ASM-NEXT: .globl var1 -; ASM-NEXT: .globl var2 -; ASM-NEXT: .weak var_l -; ASM-NEXT: .lglobl var_i -; ASM-NEXT: .globl var_h,hidden -; ASM-NEXT: .globl var_p,protected -; ASM-NEXT: .globl bitcast_alias ; ASM-NEXT: .weak fun_weak ; ASM-NEXT: .weak .fun_weak ; ASM-NEXT: .globl fun_hidden,hidden