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 @@ -28,6 +28,7 @@ #include "TargetInfo/PowerPCTargetInfo.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/ELF.h" @@ -80,6 +81,17 @@ #define DEBUG_TYPE "asmprinter" +STATISTIC(NumTOCEntries, "Number of Total TOC Entries Emitted."); +STATISTIC(NumTOCConstPool, "Number of Constant Pool TOC Entries."); +STATISTIC(NumTOCGlobalInternal, + "Number of Internal Linkage Global TOC Entries."); +STATISTIC(NumTOCGlobalExternal, + "Number of External Linkage Global TOC Entries."); +STATISTIC(NumTOCJumpTable, "Number of Jump Table TOC Entries."); +STATISTIC(NumTOCThreadLocal, "Number of Thread Local TOC Entries."); +STATISTIC(NumTOCBlockAddress, "Number of Block Address TOC Entries."); +STATISTIC(NumTOCEHBlock, "Number of EH Block TOC Entries."); + static cl::opt EnableSSPCanaryBitInTB( "aix-ssp-tb-bit", cl::init(false), cl::desc("Enable Passing SSP Canary info in Trackback on AIX"), cl::Hidden); @@ -148,7 +160,17 @@ StringRef getPassName() const override { return "PowerPC Assembly Printer"; } - MCSymbol *lookUpOrCreateTOCEntry(const MCSymbol *Sym, + enum TOCEntryType { + TOCType_ConstantPool, + TOCType_GlobalExternal, + TOCType_GlobalInternal, + TOCType_JumpTable, + TOCType_ThreadLocal, + TOCType_BlockAddress, + TOCType_EHBlock + }; + + MCSymbol *lookUpOrCreateTOCEntry(const MCSymbol *Sym, TOCEntryType Type, MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VariantKind::VK_None); @@ -412,12 +434,43 @@ return false; } +static void collectTOCStats(PPCAsmPrinter::TOCEntryType Type) { + ++NumTOCEntries; + switch (Type) { + case PPCAsmPrinter::TOCType_ConstantPool: + ++NumTOCConstPool; + break; + case PPCAsmPrinter::TOCType_GlobalInternal: + ++NumTOCGlobalInternal; + break; + case PPCAsmPrinter::TOCType_GlobalExternal: + ++NumTOCGlobalExternal; + break; + case PPCAsmPrinter::TOCType_JumpTable: + ++NumTOCJumpTable; + break; + case PPCAsmPrinter::TOCType_ThreadLocal: + ++NumTOCThreadLocal; + break; + case PPCAsmPrinter::TOCType_BlockAddress: + ++NumTOCBlockAddress; + break; + case PPCAsmPrinter::TOCType_EHBlock: + ++NumTOCEHBlock; + break; + } +} + /// lookUpOrCreateTOCEntry -- Given a symbol, look up whether a TOC entry /// exists for it. If not, create one. Then return a symbol that references /// the TOC entry. MCSymbol * -PPCAsmPrinter::lookUpOrCreateTOCEntry(const MCSymbol *Sym, +PPCAsmPrinter::lookUpOrCreateTOCEntry(const MCSymbol *Sym, TOCEntryType Type, MCSymbolRefExpr::VariantKind Kind) { + // If this is a new TOC entry add statistics about it. + if (!TOC.contains({Sym, Kind})) + collectTOCStats(Type); + MCSymbol *&TOCEntry = TOC[{Sym, Kind}]; if (!TOCEntry) TOCEntry = createTempSymbol("C"); @@ -648,6 +701,35 @@ } } +static PPCAsmPrinter::TOCEntryType +getTOCEntryTypeForMO(const MachineOperand &MO) { + // Use the target flags to determine if this MO is Thread Local. + // If we don't do this it comes out as Global. + if (MO.getTargetFlags() & PPCII::MO_TLSGDM_FLAG || + MO.getTargetFlags() & PPCII::MO_TLSGD_FLAG) + return PPCAsmPrinter::TOCType_ThreadLocal; + + switch (MO.getType()) { + case MachineOperand::MO_GlobalAddress: { + const GlobalValue *GlobalV = MO.getGlobal(); + GlobalValue::LinkageTypes Linkage = GlobalV->getLinkage(); + if (Linkage == GlobalValue::ExternalLinkage || + Linkage == GlobalValue::AvailableExternallyLinkage || + Linkage == GlobalValue::ExternalWeakLinkage) + return PPCAsmPrinter::TOCType_GlobalExternal; + + return PPCAsmPrinter::TOCType_GlobalInternal; + } + case MachineOperand::MO_ConstantPoolIndex: + return PPCAsmPrinter::TOCType_ConstantPool; + case MachineOperand::MO_JumpTableIndex: + return PPCAsmPrinter::TOCType_JumpTable; + case MachineOperand::MO_BlockAddress: + return PPCAsmPrinter::TOCType_BlockAddress; + default: + llvm_unreachable("Unexpected operand type to get TOC type."); + } +} /// EmitInstruction -- Print out a single PowerPC MI in Darwin syntax to /// the current output stream. /// @@ -865,7 +947,8 @@ // Otherwise, use the TOC. 'TOCEntry' is a label used to reference the // storage allocated in the TOC which contains the address of // 'MOSymbol'. Said TOC entry will be synthesized later. - MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol, VK); + MCSymbol *TOCEntry = + lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK); const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_None, OutContext); @@ -942,7 +1025,8 @@ // Map the machine operand to its corresponding MCSymbol, then map the // global address operand to be a reference to the TOC entry we will // synthesize later. - MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol, VK); + MCSymbol *TOCEntry = + lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK); MCSymbolRefExpr::VariantKind VKExpr = IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC; @@ -980,7 +1064,8 @@ // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to // reference the storage allocated in the TOC which contains the address of // 'MOSymbol'. - MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol, VK); + MCSymbol *TOCEntry = + lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK); const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_PPC_U, OutContext); @@ -1012,7 +1097,8 @@ // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to // reference the storage allocated in the TOC which contains the address of // 'MOSymbol'. - MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol, VK); + MCSymbol *TOCEntry = + lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK); const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_PPC_L, OutContext); @@ -1042,7 +1128,7 @@ MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal()); if (GlobalToc || MO.isJTI() || MO.isBlockAddress() || (MO.isCPI() && TM.getCodeModel() == CodeModel::Large)) - MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, VK); + MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK); VK = IsAIX ? MCSymbolRefExpr::VK_PPC_U : MCSymbolRefExpr::VK_PPC_TOC_HA; @@ -1084,7 +1170,7 @@ MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large) - MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, VK); + MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK); VK = IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO; const MCExpr *Exp = @@ -2312,7 +2398,7 @@ auto &Ctx = OutStreamer->getContext(); MCSymbol *EHInfoSym = TargetLoweringObjectFileXCOFF::getEHInfoTableSymbol(MF); - MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(EHInfoSym); + MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(EHInfoSym, TOCType_EHBlock); const MCSymbol *TOCBaseSym = cast(getObjFileLowering().getTOCBaseSection()) ->getQualNameSymbol(); @@ -2787,7 +2873,8 @@ unsigned Encoding) { if (GV) { MCSymbol *TypeInfoSym = TM.getSymbol(GV); - MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(TypeInfoSym); + MCSymbol *TOCEntry = + lookUpOrCreateTOCEntry(TypeInfoSym, TOCType_GlobalInternal); const MCSymbol *TOCBaseSym = cast(getObjFileLowering().getTOCBaseSection()) ->getQualNameSymbol(); diff --git a/llvm/test/CodeGen/PowerPC/ppc-TOC-stats.ll b/llvm/test/CodeGen/PowerPC/ppc-TOC-stats.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/ppc-TOC-stats.ll @@ -0,0 +1,239 @@ +;; Note: The checks for this test are manually generated. Please do not +;; run a script to update these checks. + +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr8 \ +; RUN: --stats < %s 2>&1 | FileCheck %s --check-prefix=AIX +; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr8 \ +; RUN: --stats < %s 2>&1 | FileCheck %s --check-prefix=AIX +; RUN: llc -verify-machineinstrs -mtriple powerpc64-unknown-linux -mcpu=pwr8 \ +; RUN: --stats < %s 2>&1 | FileCheck %s --check-prefix=LINUX +; RUN: llc -verify-machineinstrs -mtriple powerpc64le-unknown-linux -mcpu=pwr8 \ +; RUN: --stats < %s 2>&1 | FileCheck %s --check-prefix=LINUX + +; The puropose of this test is to check that the statistics about the TOC are +; are collected correctly. This test tries to have all of the different types +; of TOC entries. + +; AIX: Statistics Collected +; AIX: 1 asmprinter - Number of Block Address TOC Entries. +; AIX: 13 asmprinter - Number of Constant Pool TOC Entries. +; AIX: 1 asmprinter - Number of EH Block TOC Entries. +; AIX: 23 asmprinter - Number of Total TOC Entries Emitted. +; AIX: 3 asmprinter - Number of External Linkage Global TOC Entries. +; AIX: 2 asmprinter - Number of Internal Linkage Global TOC Entries. +; AIX: 1 asmprinter - Number of Jump Table TOC Entries. +; AIX: 2 asmprinter - Number of Thread Local TOC Entries. + +; LINUX: Statistics Collected +; LINUX: 1 asmprinter - Number of Block Address TOC Entries. +; LINUX: 5 asmprinter - Number of Total TOC Entries Emitted. +; LINUX: 3 asmprinter - Number of External Linkage Global TOC Entries. +; LINUX: 1 asmprinter - Number of Jump Table TOC Entries. + + +@gDouble = local_unnamed_addr global double 0.000000e+00, align 8 +@TLS1 = thread_local global i32 0, align 4 +@_ZTIi = external constant ptr +@_ZL2G4 = internal unnamed_addr global i32 0, align 4 +@_ZZ9incrementvE7Element = internal unnamed_addr global i32 0, align 4 + +define noundef double @testd1() local_unnamed_addr { +entry: + ret double 3.784320e+02 +} + +define noundef float @testf1() local_unnamed_addr { +entry: + ret float 0x40039999A0000000 +} + +define noundef double @testd2() local_unnamed_addr { +entry: + ret double 6.920000e+00 +} + +define noundef <4 x i32> @testv1() local_unnamed_addr { +entry: + ret <4 x i32> +} + +define noundef double @testd3() local_unnamed_addr { +entry: + %call = tail call noundef double @calleeddf(double noundef 4.582600e+01, double noundef 0x40564F0A3D70A3D7, float noundef 0x402225E360000000) + ret double %call +} + +declare noundef double @calleeddf(double noundef, double noundef, float noundef) local_unnamed_addr + +define noundef i64 @testi() local_unnamed_addr { +entry: + ret i64 893471915 +} + +define noundef double @testld1() local_unnamed_addr { +entry: + ret double 0x417179806D5CDEBE +} + +define noundef signext i32 @testJT(i32 noundef signext %in) { +entry: + switch i32 %in, label %sw.epilog [ + i32 45, label %return + i32 86, label %sw.bb1 + i32 91, label %sw.bb2 + i32 101, label %sw.bb3 + i32 107, label %sw.bb4 + i32 76832712, label %sw.bb5 + ] + +sw.bb1: ; preds = %entry + br label %return + +sw.bb2: ; preds = %entry + br label %return + +sw.bb3: ; preds = %entry + br label %return + +sw.bb4: ; preds = %entry + br label %return + +sw.bb5: ; preds = %entry + br label %return + +sw.epilog: ; preds = %entry + br label %return + +return: ; preds = %entry, %sw.epilog, %sw.bb5, %sw.bb4, %sw.bb3, %sw.bb2, %sw.bb1 + %retval.0 = phi i32 [ 0, %sw.epilog ], [ 222, %sw.bb5 ], [ 15, %sw.bb4 ], [ 11, %sw.bb3 ], [ 17, %sw.bb2 ], [ 16, %sw.bb1 ], [ 19, %entry ] + ret i32 %retval.0 +} + +define void @setGDouble(double noundef %a) local_unnamed_addr { +entry: + store double %a, ptr @gDouble, align 8 + ret void +} + +define noundef double @getGDouble() local_unnamed_addr { +entry: + %0 = load double, ptr @gDouble, align 8 + ret double %0 +} + +define noundef signext i32 @testTLS(i32 noundef signext %a, i32 noundef signext %b, ptr nocapture noundef readonly %fIn) { +entry: + %add = add nsw i32 %b, %a + %0 = tail call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @TLS1) + store i32 %add, ptr %0, align 4 + tail call void @calleef(ptr noundef nonnull @testJT) + %1 = load i32, ptr %0, align 4 + %call = tail call noundef signext i32 %fIn(i32 noundef signext %1) + %2 = load i32, ptr %0, align 4 + %add1 = add nsw i32 %2, %call + ret i32 %add1 +} + +declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull) +declare void @calleef(ptr noundef) local_unnamed_addr + +define noundef signext i32 @testEH(i32 noundef signext %i) personality ptr @__xlcxx_personality_v1 { +entry: + %cmp = icmp slt i32 %i, 1 + br i1 %cmp, label %if.then, label %try.cont + +if.then: ; preds = %entry + %exception = tail call ptr @__cxa_allocate_exception(i64 4) + store i32 10, ptr %exception, align 16 + invoke void @__cxa_throw(ptr nonnull %exception, ptr nonnull @_ZTIi, ptr null) + to label %unreachable unwind label %lpad + +lpad: ; preds = %if.then + %0 = landingpad { ptr, i32 } + cleanup + catch ptr @_ZTIi + %1 = extractvalue { ptr, i32 } %0, 1 + %2 = tail call i32 @llvm.eh.typeid.for(ptr nonnull @_ZTIi) + %matches = icmp eq i32 %1, %2 + br i1 %matches, label %catch, label %ehcleanup + +catch: ; preds = %lpad + %3 = extractvalue { ptr, i32 } %0, 0 + %4 = tail call ptr @__cxa_begin_catch(ptr %3) + tail call void @__cxa_end_catch() + br label %try.cont + +try.cont: ; preds = %entry, %catch + %ret.0 = phi i32 [ 1, %catch ], [ 0, %entry ] + ret i32 %ret.0 + +ehcleanup: ; preds = %lpad + resume { ptr, i32 } %0 + +unreachable: ; preds = %if.then + unreachable +} + +declare ptr @__cxa_allocate_exception(i64) local_unnamed_addr +declare void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr +declare i32 @__xlcxx_personality_v1(...) +declare i32 @llvm.eh.typeid.for(ptr) +declare ptr @__cxa_begin_catch(ptr) local_unnamed_addr +declare void @__cxa_end_catch() local_unnamed_addr + +define noundef double @testISel1(i32 noundef signext %i) { +entry: + %cmp = icmp slt i32 %i, 0 + %cmp1.not = icmp eq i32 %i, 0 + %. = select i1 %cmp1.not, double 1.618030e+00, double 2.718280e+00 + %retval.0 = select i1 %cmp, double 3.141590e+00, double %. + ret double %retval.0 +} + +define noundef double @testISel2(i32 noundef signext %i) { +entry: + %cmp = icmp slt i32 %i, 0 + br i1 %cmp, label %return, label %if.else + +if.else: ; preds = %entry + %cmp1 = icmp ugt i32 %i, 30 + br i1 %cmp1, label %return, label %if.else3 + +if.else3: ; preds = %if.else + %cmp4 = icmp ugt i32 %i, 5 + %. = select i1 %cmp4, double 8.644600e+00, double 1.618030e+00 + br label %return + +return: ; preds = %if.else3, %if.else, %entry + %retval.0 = phi double [ 3.141590e+00, %entry ], [ 2.718280e+00, %if.else ], [ %., %if.else3 ] + ret double %retval.0 +} + + +define i8* @testBlockAddr() { +entry: + br label %here + +here: + ret i8* blockaddress(@testBlockAddr, %here) +} + +define noundef signext i32 @_Z5getG4v() local_unnamed_addr { +entry: + %0 = load i32, ptr @_ZL2G4, align 4 + ret i32 %0 +} + +define void @_Z5setG4i(i32 noundef signext %value) local_unnamed_addr { +entry: + store i32 %value, ptr @_ZL2G4, align 4 + ret void +} + +define noundef signext i32 @_Z9incrementv() local_unnamed_addr { +entry: + %0 = load i32, ptr @_ZZ9incrementvE7Element, align 4 + %inc = add nsw i32 %0, 1 + store i32 %inc, ptr @_ZZ9incrementvE7Element, align 4 + ret i32 %inc +}