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 points 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 @@ -1790,6 +1790,9 @@ 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. @@ -2848,7 +2851,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); @@ -2944,7 +2948,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); @@ -2952,10 +2957,10 @@ if (Value != -1) { uint64_t Bytes = DL.getTypeAllocSize(CA->getType()); AP.OutStreamer->emitFill(Bytes, Value); - } - else { + } else { for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { - emitGlobalConstantImpl(DL, CA->getOperand(i), AP, BaseCV, Offset); + emitGlobalConstantImpl(DL, CA->getOperand(i), AP, BaseCV, Offset, + AliasList); Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType()); } } @@ -2975,7 +2980,8 @@ 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()); @@ -2984,7 +2990,8 @@ 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()); @@ -3199,7 +3206,17 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV, AsmPrinter &AP, const Constant *BaseCV, - uint64_t Offset) { + 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); + } + } + uint64_t Size = DL.getTypeAllocSize(CV->getType()); // Globals with sub-elements such as combinations of arrays and structs @@ -3242,10 +3259,10 @@ return emitGlobalConstantDataSequential(DL, CDS, AP); 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 @@ -3280,10 +3297,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,22 @@ .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."); + if (auto *RHS = dyn_cast(CBE->getRHS())) + 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 +2441,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.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