diff --git a/llvm/lib/Target/PowerPC/CMakeLists.txt b/llvm/lib/Target/PowerPC/CMakeLists.txt --- a/llvm/lib/Target/PowerPC/CMakeLists.txt +++ b/llvm/lib/Target/PowerPC/CMakeLists.txt @@ -41,6 +41,7 @@ PPCMachineFunctionInfo.cpp PPCMachineScheduler.cpp PPCMacroFusion.cpp + PPCMergeStringPool.cpp PPCMIPeephole.cpp PPCRegisterInfo.cpp PPCSubtarget.cpp diff --git a/llvm/lib/Target/PowerPC/PPC.h b/llvm/lib/Target/PowerPC/PPC.h --- a/llvm/lib/Target/PowerPC/PPC.h +++ b/llvm/lib/Target/PowerPC/PPC.h @@ -53,6 +53,7 @@ FunctionPass *createPPCPreEmitPeepholePass(); FunctionPass *createPPCExpandAtomicPseudoPass(); FunctionPass *createPPCCTRLoopsPass(); + ModulePass *createPPCMergeStringPoolPass(); void LowerPPCMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, AsmPrinter &AP); bool LowerPPCMachineOperandToMCOperand(const MachineOperand &MO, @@ -78,6 +79,7 @@ void initializePPCExpandAtomicPseudoPass(PassRegistry &); void initializePPCCTRLoopsPass(PassRegistry &); void initializePPCDAGToDAGISelPass(PassRegistry &); + void initializePPCMergeStringPoolPass(PassRegistry &); extern char &PPCVSXFMAMutateID; diff --git a/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp b/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp @@ -0,0 +1,312 @@ +//===-- PPCMergeStringPool.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This transformation tries to merge the strings in the module into one pool +// of strings. The idea is to reduce the number of TOC entries in the module so +// that instead of having one TOC entry for each string there is only one global +// TOC entry and all of the strings are referenced off of that one entry plus +// an offset. +// +//===----------------------------------------------------------------------===// + +#include "PPC.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/DomTreeUpdater.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/LoopIterator.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" + +#define DEBUG_TYPE "ppc-merge-strings" + +STATISTIC(NumPooledStrings, "Number of Strings Pooled"); + +using namespace llvm; + +static cl::opt + MaxStringsPooled("ppc-max-strings-pooled", cl::Hidden, cl::init(-1), + cl::desc("Maximum Number of Strings to Pool.")); + +namespace { +struct { + bool operator()(const GlobalVariable *LHS, const GlobalVariable *RHS) const { + // First priority is alignment. + // If elements are sorted in terms of alignment then there won't be an + // issue with incorrect alignent that would require padding. + Align LHSAlign = LHS->getAlign().valueOrOne(); + Align RHSAlign = RHS->getAlign().valueOrOne(); + if (LHSAlign > RHSAlign) + return true; + else if (LHSAlign < RHSAlign) + return false; + + // Next priority is the number of uses. + // Theoretically smaller offsets are easier to materialize. + if (LHS->getNumUses() > RHS->getNumUses()) + return true; + if (LHS->getNumUses() < RHS->getNumUses()) + return false; + + const Constant *ConstLHS = LHS->getInitializer(); + const ConstantDataSequential *ConstDataLHS = + dyn_cast(ConstLHS); + unsigned LHSSize = + ConstDataLHS->getNumElements() * ConstDataLHS->getElementByteSize(); + const Constant *ConstRHS = RHS->getInitializer(); + const ConstantDataSequential *ConstDataRHS = + dyn_cast(ConstRHS); + unsigned RHSSize = + ConstDataRHS->getNumElements() * ConstDataRHS->getElementByteSize(); + + // Finally smaller constants should go first. This is, again, trying to + // minimize the offsets into the final struct. + return LHSSize < RHSSize; + } +} CompareConstants; + +class PPCMergeStringPool : public ModulePass { +public: + static char ID; + PPCMergeStringPool() : ModulePass(ID) {} + + bool runOnModule(Module &M) override; + + StringRef getPassName() const override { return "PPC Merge String Pool"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addPreserved(); + AU.addPreserved(); + AU.addPreserved(); + AU.addPreserved(); + } + +private: + // Globals in a Module are already unique so a set is not required and a + // vector will do. + std::vector ConstsToMerge; + Type *PooledStructType; + LLVMContext *Context; + void collectCandidateConstants(Module &M); + bool mergeModuleStringPool(Module &M); + void insertGEPBeforeUser(SmallVector &UsersList, + GlobalVariable *GToReplace, GlobalVariable *GPool, + unsigned ElementIndex); +}; + +} // namespace + +bool PPCMergeStringPool::runOnModule(Module &M) { + bool Changed = false; + Context = &M.getContext(); + + Changed = mergeModuleStringPool(M); + return Changed; +} + +static bool hasValidUsers(GlobalVariable &GV) { + for (User *CurrentUser : GV.users()) { + // Instruction users are always valid. + if (dyn_cast(CurrentUser)) + continue; + + if (Constant *UserConstant = dyn_cast(CurrentUser)) { + // We can replace all Constant users except GlobalValues. + if (dyn_cast(UserConstant)) + return false; + } else + return false; + } + + return true; +} + +void PPCMergeStringPool::collectCandidateConstants(Module &M) { + for (GlobalVariable &Global : M.globals()) { + LLVM_DEBUG(dbgs() << "Looking at global:"); + LLVM_DEBUG(Global.dump()); + LLVM_DEBUG(dbgs() << "isConstant() " << Global.isConstant() << "\n"); + LLVM_DEBUG(dbgs() << "hasInitializer() " << Global.hasInitializer() + << "\n"); + + // We can only pool constants. + if (!Global.isConstant() || !Global.hasInitializer()) + continue; + + if (Global.hasSection()) + continue; + + if (Global.hasMetadata()) + continue; + + Constant *Const = Global.getInitializer(); + ConstantDataSequential *ConstData = dyn_cast(Const); + + if (!ConstData) + continue; + + if (!hasValidUsers(Global)) + continue; + + LLVM_DEBUG(dbgs() << "Have constant data: "); + LLVM_DEBUG(ConstData->dump()); + LLVM_DEBUG(dbgs() << "\n\n"); + + ConstsToMerge.push_back(&Global); + + // If we have already reached the maximum number of pooled strings then + // there is no point in looking for more. + if (ConstsToMerge.size() >= MaxStringsPooled) + break; + } +} + +bool PPCMergeStringPool::mergeModuleStringPool(Module &M) { + + LLVM_DEBUG(dbgs() << "Merging string pool for module: " << M.getName() + << "\n"); + LLVM_DEBUG(dbgs() << "Number of globals is: " << M.global_size() << "\n"); + + collectCandidateConstants(M); + + // If we only have one (or fewer) constants in the module that are merge + // candidates we can skip doing the merging. + if (ConstsToMerge.size() <= 1) + return false; + + // Sort the global constants to make access more efficient. + std::sort(ConstsToMerge.begin(), ConstsToMerge.end(), CompareConstants); + + SmallVector OrderedVector; + for (GlobalVariable *GV : ConstsToMerge) { + OrderedVector.push_back(GV->getInitializer()); + } + + // Use an anonymous struct to pool the strings. + Constant *AnonStruct = ConstantStruct::getAnon(OrderedVector); + PooledStructType = AnonStruct->getType(); + + // The GlobalVariable constructor calls MM->insertGlobalVariable(G). + GlobalVariable *G = + new GlobalVariable(M, AnonStruct->getType(), + /* isConstant */ true, GlobalValue::PrivateLinkage, + AnonStruct, "__ModuleStringPool"); + + LLVM_DEBUG(dbgs() << "Constructing global variable for string pool: "); + LLVM_DEBUG(G->dump()); + + unsigned ElementIndex = 0; + for (GlobalVariable *GV : ConstsToMerge) { + + LLVM_DEBUG(dbgs() << "The global:\n"); + LLVM_DEBUG(GV->dump()); + LLVM_DEBUG(dbgs() << "Has " << GV->getNumUses() << " uses.\n"); + + // Need to save a temporary copy of each use list because we remove uses + // as we replace them. + SmallVector UserList; + for (User *CurrentUser : GV->users()) + UserList.push_back(CurrentUser); + + insertGEPBeforeUser(UserList, GV, G, ElementIndex); + + // This GV has no more uses and is privately linked so we can erase it. + if (GV->use_empty() && GV->getLinkage() == GlobalValue::PrivateLinkage) + GV->eraseFromParent(); + + NumPooledStrings++; + ElementIndex++; + } + return true; +} + +static bool userHasOperand(User *TheUser, GlobalVariable *GVOperand) { + for (Value *Op : TheUser->operands()) + if (Op == GVOperand) + return true; + + return false; +} + +void PPCMergeStringPool::insertGEPBeforeUser(SmallVector &UsersList, + GlobalVariable *GToReplace, + GlobalVariable *GPool, + unsigned ElementIndex) { + ConstantInt *Zero = ConstantInt::get(Type::getInt32Ty(*Context), 0); + ConstantInt *Index = + ConstantInt::get(Type::getInt32Ty(*Context), ElementIndex); + SmallVector Indices; + Indices.push_back(Zero); + Indices.push_back(Index); + + for (User *CurrentUser : UsersList) { + Instruction *UseInstruction = dyn_cast(CurrentUser); + + // The user is a valid instruction. + if (UseInstruction) { + // GEP instructions cannot be added before PHI nodes. + if (PHINode *UsePHI = dyn_cast(UseInstruction)) { + Constant *ConstGEP = ConstantExpr::getInBoundsGetElementPtr( + PooledStructType, GPool, Indices); + UsePHI->replaceUsesOfWith(GToReplace, ConstGEP); + continue; + } + + GetElementPtrInst *GEPInst = + GetElementPtrInst::Create(PooledStructType, GPool, Indices); + GEPInst->insertBefore(UseInstruction); + + LLVM_DEBUG(dbgs() << "Inserting GEP before:\n"); + LLVM_DEBUG(UseInstruction->dump()); + + LLVM_DEBUG(dbgs() << "Replacing this global:\n"); + LLVM_DEBUG(GToReplace->dump()); + LLVM_DEBUG(dbgs() << "with this:\n"); + LLVM_DEBUG(GEPInst->dump()); + + // After the GEP is insterted the GV can be replaced. + CurrentUser->replaceUsesOfWith(GToReplace, GEPInst); + continue; + } + + Constant *ConstGEP = ConstantExpr::getInBoundsGetElementPtr( + PooledStructType, GPool, Indices); + Constant *UserConstant = dyn_cast(CurrentUser); + + // At this point we expect that the user is either an instruction or a + // constant. + assert(UserConstant && + "Expected the user to be an instruction or a constant."); + + // We cannot replace operands in globals so we ignore those. + if (dyn_cast(UserConstant)) + continue; + + // The use was not found so it must have been replaced earlier. + if (!userHasOperand(UserConstant, GToReplace)) + continue; + + UserConstant->handleOperandChange(GToReplace, ConstGEP); + } +} + +char PPCMergeStringPool::ID = 0; + +INITIALIZE_PASS(PPCMergeStringPool, DEBUG_TYPE, "PPC Merge String Pool", false, + false) + +ModulePass *llvm::createPPCMergeStringPoolPass() { + return new PPCMergeStringPool(); +} diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp --- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp +++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp @@ -100,6 +100,12 @@ cl::desc("Expand eligible cr-logical binary ops to branches"), cl::init(true), cl::Hidden); +static cl::opt + MergeStringPool("ppc-merge-string-pool", + cl::desc("Merge all of strings in a module into one pool"), + cl::init(false), cl::Hidden); + + static cl::opt EnablePPCGenScalarMASSEntries( "enable-ppc-gen-scalar-mass", cl::init(false), cl::desc("Enable lowering math functions to their corresponding MASS " @@ -137,6 +143,7 @@ initializeGlobalISel(PR); initializePPCCTRLoopsPass(PR); initializePPCDAGToDAGISelPass(PR); + initializePPCMergeStringPoolPass(PR); } static bool isLittleEndianTriple(const Triple &T) { @@ -484,6 +491,9 @@ } bool PPCPassConfig::addPreISel() { + if (MergeStringPool && getOptLevel() != CodeGenOpt::None) + addPass(createPPCMergeStringPoolPass()); + if (!DisableInstrFormPrep && getOptLevel() != CodeGenOpt::None) addPass(createPPCLoopInstrFormPrepPass(getPPCTargetMachine())); diff --git a/llvm/test/CodeGen/PowerPC/stringpool.ll b/llvm/test/CodeGen/PowerPC/stringpool.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/stringpool.ll @@ -0,0 +1,1059 @@ +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr8 \ +; RUN: -ppc-merge-string-pool=true < %s | FileCheck %s --check-prefixes=AIX32,AIXDATA +; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr8 \ +; RUN: -ppc-merge-string-pool=true < %s | FileCheck %s --check-prefixes=AIX64,AIXDATA +; RUN: llc -verify-machineinstrs -mtriple powerpc64-unknown-linux -mcpu=pwr8 \ +; RUN: -ppc-merge-string-pool=true < %s | FileCheck %s --check-prefixes=LINUX64BE,LINUXDATA +; RUN: llc -verify-machineinstrs -mtriple powerpc64le-unknown-linux -mcpu=pwr8 \ +; RUN: -ppc-merge-string-pool=true < %s | FileCheck %s --check-prefixes=LINUX64LE,LINUXDATA + +@.str = private unnamed_addr constant [47 x i8] c"This is the global string that is at the top.\0A\00", align 1 +@GLOBALSTRING = dso_local local_unnamed_addr global ptr @.str, align 8 +@IntArray2 = dso_local global [7 x i32] [i32 5, i32 7, i32 9, i32 11, i32 17, i32 1235, i32 32], align 4 +@.str.1 = private unnamed_addr constant [12 x i8] c"str1_STRING\00", align 1 +@.str.2 = private unnamed_addr constant [12 x i8] c"str2_STRING\00", align 1 +@.str.3 = private unnamed_addr constant [12 x i8] c"str3_STRING\00", align 1 +@.str.4 = private unnamed_addr constant [12 x i8] c"str4_STRING\00", align 1 +@.str.5 = private unnamed_addr constant [183 x i8] c"longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_STRING\00", align 1 +@__const.str6.TheString = private unnamed_addr constant [10 x i8] c"ABCABCABC\00", align 1 +@.str.6 = private unnamed_addr constant [12 x i8] c"MixedString\00", align 1 +@__const.mixed2.IntArray = private unnamed_addr constant [7 x i32] [i32 5, i32 7, i32 9, i32 11, i32 17, i32 1235, i32 32], align 4 +@.str.7 = private unnamed_addr constant [20 x i8] c"Different String 01\00", align 1 +@.str.8 = private unnamed_addr constant [15 x i8] c"Static Global\0A\00", align 1 + +define dso_local signext i32 @str1() local_unnamed_addr #0 { +; AIX32-LABEL: str1: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -64(1) +; AIX32-NEXT: lwz 3, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: stw 0, 72(1) +; AIX32-NEXT: addi 3, 3, 62 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 1, 1, 64 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: str1: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -112(1) +; AIX64-NEXT: ld 3, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: std 0, 128(1) +; AIX64-NEXT: addi 3, 3, 62 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: addi 1, 1, 112 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: str1: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -112(1) +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: std 0, 128(1) +; LINUX64BE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: addi 3, 3, 62 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: addi 1, 1, 112 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: str1: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: stdu 1, -32(1) +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: std 0, 48(1) +; LINUX64LE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: addi 3, 3, 62 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: addi 1, 1, 32 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %call = tail call signext i32 @callee(ptr noundef nonnull @.str.1) + ret i32 %call +} + +declare signext i32 @callee(ptr noundef) local_unnamed_addr + +define dso_local signext i32 @str2() local_unnamed_addr #0 { +; AIX32-LABEL: str2: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -64(1) +; AIX32-NEXT: lwz 3, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: stw 0, 72(1) +; AIX32-NEXT: addi 3, 3, 28 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 1, 1, 64 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: str2: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -112(1) +; AIX64-NEXT: ld 3, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: std 0, 128(1) +; AIX64-NEXT: addi 3, 3, 28 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: addi 1, 1, 112 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: str2: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -112(1) +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: std 0, 128(1) +; LINUX64BE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: addi 3, 3, 28 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: addi 1, 1, 112 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: str2: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: stdu 1, -32(1) +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: std 0, 48(1) +; LINUX64LE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: addi 3, 3, 28 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: addi 1, 1, 32 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %call = tail call signext i32 @callee(ptr noundef nonnull @.str.2) + ret i32 %call +} + +define dso_local signext i32 @str3() local_unnamed_addr #0 { +; AIX32-LABEL: str3: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -64(1) +; AIX32-NEXT: stw 0, 72(1) +; AIX32-NEXT: stw 31, 60(1) # 4-byte Folded Spill +; AIX32-NEXT: lwz 31, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: addi 3, 31, 74 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 4, 31, 28 +; AIX32-NEXT: mr 31, 3 +; AIX32-NEXT: mr 3, 4 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: add 3, 3, 31 +; AIX32-NEXT: lwz 31, 60(1) # 4-byte Folded Reload +; AIX32-NEXT: addi 1, 1, 64 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: str3: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -128(1) +; AIX64-NEXT: std 0, 144(1) +; AIX64-NEXT: std 30, 112(1) # 8-byte Folded Spill +; AIX64-NEXT: ld 30, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: std 31, 120(1) # 8-byte Folded Spill +; AIX64-NEXT: addi 3, 30, 74 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: mr 31, 3 +; AIX64-NEXT: addi 3, 30, 28 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: add 3, 3, 31 +; AIX64-NEXT: ld 31, 120(1) # 8-byte Folded Reload +; AIX64-NEXT: ld 30, 112(1) # 8-byte Folded Reload +; AIX64-NEXT: extsw 3, 3 +; AIX64-NEXT: addi 1, 1, 128 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: str3: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -144(1) +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: std 0, 160(1) +; LINUX64BE-NEXT: std 29, 120(1) # 8-byte Folded Spill +; LINUX64BE-NEXT: std 30, 128(1) # 8-byte Folded Spill +; LINUX64BE-NEXT: addi 29, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: addi 3, 29, 74 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: mr 30, 3 +; LINUX64BE-NEXT: addi 3, 29, 28 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: add 3, 3, 30 +; LINUX64BE-NEXT: ld 30, 128(1) # 8-byte Folded Reload +; LINUX64BE-NEXT: ld 29, 120(1) # 8-byte Folded Reload +; LINUX64BE-NEXT: extsw 3, 3 +; LINUX64BE-NEXT: addi 1, 1, 144 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: str3: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: std 29, -24(1) # 8-byte Folded Spill +; LINUX64LE-NEXT: std 30, -16(1) # 8-byte Folded Spill +; LINUX64LE-NEXT: stdu 1, -64(1) +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: std 0, 80(1) +; LINUX64LE-NEXT: addi 29, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: addi 3, 29, 74 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: mr 30, 3 +; LINUX64LE-NEXT: addi 3, 29, 28 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: add 3, 3, 30 +; LINUX64LE-NEXT: extsw 3, 3 +; LINUX64LE-NEXT: addi 1, 1, 64 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: ld 30, -16(1) # 8-byte Folded Reload +; LINUX64LE-NEXT: ld 29, -24(1) # 8-byte Folded Reload +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %call = tail call signext i32 @callee(ptr noundef nonnull @.str.3) + %call1 = tail call signext i32 @callee(ptr noundef nonnull @.str.2) + %add = add nsw i32 %call1, %call + ret i32 %add +} + +define dso_local signext i32 @str4() local_unnamed_addr #0 { +; AIX32-LABEL: str4: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -64(1) +; AIX32-NEXT: lwz 3, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: stw 0, 72(1) +; AIX32-NEXT: addi 3, 3, 86 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 1, 1, 64 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: str4: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -112(1) +; AIX64-NEXT: ld 3, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: std 0, 128(1) +; AIX64-NEXT: addi 3, 3, 86 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: addi 1, 1, 112 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: str4: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -112(1) +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: std 0, 128(1) +; LINUX64BE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: addi 3, 3, 86 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: addi 1, 1, 112 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: str4: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: stdu 1, -32(1) +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: std 0, 48(1) +; LINUX64LE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: addi 3, 3, 86 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: addi 1, 1, 32 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %call = tail call signext i32 @callee(ptr noundef nonnull @.str.4) + ret i32 %call +} + +define dso_local signext i32 @str5() local_unnamed_addr #0 { +; AIX32-LABEL: str5: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -64(1) +; AIX32-NEXT: lwz 3, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: stw 0, 72(1) +; AIX32-NEXT: addi 3, 3, 133 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 1, 1, 64 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: str5: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -112(1) +; AIX64-NEXT: ld 3, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: std 0, 128(1) +; AIX64-NEXT: addi 3, 3, 133 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: addi 1, 1, 112 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: str5: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -112(1) +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: std 0, 128(1) +; LINUX64BE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: addi 3, 3, 133 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: addi 1, 1, 112 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: str5: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: stdu 1, -32(1) +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: std 0, 48(1) +; LINUX64LE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: addi 3, 3, 133 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: addi 1, 1, 32 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %call = tail call signext i32 @callee(ptr noundef nonnull @.str.5) + ret i32 %call +} + +define dso_local signext i32 @array1() local_unnamed_addr #0 { +; AIX32-LABEL: array1: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -96(1) +; AIX32-NEXT: lwz 4, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: li 5, 12 +; AIX32-NEXT: addi 3, 1, 64 +; AIX32-NEXT: stw 0, 104(1) +; AIX32-NEXT: lxvw4x 0, 4, 5 +; AIX32-NEXT: lxvw4x 1, 0, 4 +; AIX32-NEXT: mr 4, 3 +; AIX32-NEXT: rlwimi 4, 5, 0, 28, 29 +; AIX32-NEXT: stxvw4x 0, 0, 4 +; AIX32-NEXT: stxvw4x 1, 0, 3 +; AIX32-NEXT: bl .calleeInt[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 1, 1, 96 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: array1: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -144(1) +; AIX64-NEXT: ld 3, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: li 4, 12 +; AIX64-NEXT: std 0, 160(1) +; AIX64-NEXT: lxvw4x 0, 3, 4 +; AIX64-NEXT: lxvw4x 1, 0, 3 +; AIX64-NEXT: addi 4, 1, 124 +; AIX64-NEXT: addi 3, 1, 112 +; AIX64-NEXT: stxvw4x 0, 0, 4 +; AIX64-NEXT: stxvw4x 1, 0, 3 +; AIX64-NEXT: bl .calleeInt[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: addi 1, 1, 144 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: array1: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -144(1) +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: li 4, 12 +; LINUX64BE-NEXT: std 0, 160(1) +; LINUX64BE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: lxvw4x 0, 3, 4 +; LINUX64BE-NEXT: lxvw4x 1, 0, 3 +; LINUX64BE-NEXT: addi 4, 1, 124 +; LINUX64BE-NEXT: addi 3, 1, 112 +; LINUX64BE-NEXT: stxvw4x 0, 0, 4 +; LINUX64BE-NEXT: stxvw4x 1, 0, 3 +; LINUX64BE-NEXT: bl calleeInt +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: addi 1, 1, 144 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: array1: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: stdu 1, -64(1) +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: li 4, 12 +; LINUX64LE-NEXT: std 0, 80(1) +; LINUX64LE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: lxvd2x 0, 3, 4 +; LINUX64LE-NEXT: lxvd2x 1, 0, 3 +; LINUX64LE-NEXT: addi 4, 1, 44 +; LINUX64LE-NEXT: addi 3, 1, 32 +; LINUX64LE-NEXT: stxvd2x 0, 0, 4 +; LINUX64LE-NEXT: stxvd2x 1, 0, 3 +; LINUX64LE-NEXT: bl calleeInt +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: addi 1, 1, 64 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %IntArray = alloca [7 x i32], align 4 + call void @llvm.lifetime.start.p0(i64 28, ptr nonnull %IntArray) + call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(28) %IntArray, ptr noundef nonnull align 4 dereferenceable(28) @__const.mixed2.IntArray, i64 28, i1 false) + %call = call signext i32 @calleeInt(ptr noundef nonnull %IntArray) + call void @llvm.lifetime.end.p0(i64 28, ptr nonnull %IntArray) + ret i32 %call +} + +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) +declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) +declare signext i32 @calleeInt(ptr noundef) local_unnamed_addr +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) + +define dso_local double @DValue1() local_unnamed_addr #0 { +; LINUX-LABEL: DValue1: +; LINUX: # %bb.0: # %entry +; LINUX-NEXT: addis 3, 2, .LCPI6_0@toc@ha +; LINUX-NEXT: lfd 1, .LCPI6_0@toc@l(3) +; LINUX-NEXT: blr +; AIX32-LABEL: DValue1: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: lwz 3, L..C1(2) # %const.0 +; AIX32-NEXT: lfd 1, 0(3) +; AIX32-NEXT: blr +; +; AIX64-LABEL: DValue1: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: ld 3, L..C1(2) # %const.0 +; AIX64-NEXT: lfd 1, 0(3) +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: DValue1: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: addis 3, 2, .LCPI6_0@toc@ha +; LINUX64BE-NEXT: lfd 1, .LCPI6_0@toc@l(3) +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: DValue1: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: addis 3, 2, .LCPI6_0@toc@ha +; LINUX64LE-NEXT: lfd 1, .LCPI6_0@toc@l(3) +; LINUX64LE-NEXT: blr +entry: + ret double 3.141590e+00 +} + +define dso_local signext i32 @str6() local_unnamed_addr #0 { +; AIX32-LABEL: str6: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -80(1) +; AIX32-NEXT: li 3, 17152 +; AIX32-NEXT: lis 4, 16963 +; AIX32-NEXT: stw 0, 88(1) +; AIX32-NEXT: lis 5, 16706 +; AIX32-NEXT: sth 3, 72(1) +; AIX32-NEXT: ori 3, 4, 16706 +; AIX32-NEXT: ori 4, 5, 17217 +; AIX32-NEXT: stw 31, 76(1) # 4-byte Folded Spill +; AIX32-NEXT: stw 3, 68(1) +; AIX32-NEXT: addi 3, 1, 64 +; AIX32-NEXT: stw 4, 64(1) +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 4, 1, 69 +; AIX32-NEXT: mr 31, 3 +; AIX32-NEXT: mr 3, 4 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: add 3, 3, 31 +; AIX32-NEXT: lwz 31, 76(1) # 4-byte Folded Reload +; AIX32-NEXT: addi 1, 1, 80 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: str6: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -144(1) +; AIX64-NEXT: lis 3, 16706 +; AIX64-NEXT: std 0, 160(1) +; AIX64-NEXT: li 4, 17152 +; AIX64-NEXT: std 31, 136(1) # 8-byte Folded Spill +; AIX64-NEXT: ori 3, 3, 17217 +; AIX64-NEXT: rldic 3, 3, 32, 1 +; AIX64-NEXT: oris 3, 3, 16963 +; AIX64-NEXT: sth 4, 128(1) +; AIX64-NEXT: ori 3, 3, 16706 +; AIX64-NEXT: std 3, 120(1) +; AIX64-NEXT: addi 3, 1, 120 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: mr 31, 3 +; AIX64-NEXT: addi 3, 1, 125 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: add 3, 3, 31 +; AIX64-NEXT: ld 31, 136(1) # 8-byte Folded Reload +; AIX64-NEXT: extsw 3, 3 +; AIX64-NEXT: addi 1, 1, 144 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: str6: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -144(1) +; LINUX64BE-NEXT: lis 3, 16706 +; LINUX64BE-NEXT: std 0, 160(1) +; LINUX64BE-NEXT: li 4, 17152 +; LINUX64BE-NEXT: std 30, 128(1) # 8-byte Folded Spill +; LINUX64BE-NEXT: ori 3, 3, 17217 +; LINUX64BE-NEXT: rldic 3, 3, 32, 1 +; LINUX64BE-NEXT: oris 3, 3, 16963 +; LINUX64BE-NEXT: sth 4, 120(1) +; LINUX64BE-NEXT: ori 3, 3, 16706 +; LINUX64BE-NEXT: std 3, 112(1) +; LINUX64BE-NEXT: addi 3, 1, 112 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: mr 30, 3 +; LINUX64BE-NEXT: addi 3, 1, 117 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: add 3, 3, 30 +; LINUX64BE-NEXT: ld 30, 128(1) # 8-byte Folded Reload +; LINUX64BE-NEXT: extsw 3, 3 +; LINUX64BE-NEXT: addi 1, 1, 144 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: str6: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: std 30, -16(1) # 8-byte Folded Spill +; LINUX64LE-NEXT: stdu 1, -64(1) +; LINUX64LE-NEXT: lis 3, 8480 +; LINUX64LE-NEXT: std 0, 80(1) +; LINUX64LE-NEXT: li 4, 67 +; LINUX64LE-NEXT: ori 3, 3, 41377 +; LINUX64LE-NEXT: sth 4, 40(1) +; LINUX64LE-NEXT: rldic 3, 3, 33, 1 +; LINUX64LE-NEXT: oris 3, 3, 16707 +; LINUX64LE-NEXT: ori 3, 3, 16961 +; LINUX64LE-NEXT: std 3, 32(1) +; LINUX64LE-NEXT: addi 3, 1, 32 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: mr 30, 3 +; LINUX64LE-NEXT: addi 3, 1, 37 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: add 3, 3, 30 +; LINUX64LE-NEXT: extsw 3, 3 +; LINUX64LE-NEXT: addi 1, 1, 64 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: ld 30, -16(1) # 8-byte Folded Reload +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %TheString = alloca [10 x i8], align 1 + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %TheString) + call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(10) %TheString, ptr noundef nonnull align 1 dereferenceable(10) @__const.str6.TheString, i64 10, i1 false) + %call = call signext i32 @callee(ptr noundef nonnull %TheString) + %add.ptr = getelementptr inbounds i8, ptr %TheString, i64 5 + %call2 = call signext i32 @callee(ptr noundef nonnull %add.ptr) + %add = add nsw i32 %call2, %call + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %TheString) + ret i32 %add +} + +define dso_local signext i32 @str7() local_unnamed_addr #0 { +; AIX32-LABEL: str7: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -64(1) +; AIX32-NEXT: lwz 3, L..C2(2) # @GLOBALSTRING +; AIX32-NEXT: stw 0, 72(1) +; AIX32-NEXT: stw 31, 60(1) # 4-byte Folded Spill +; AIX32-NEXT: lwz 3, 0(3) +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: lwz 4, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: mr 31, 3 +; AIX32-NEXT: addi 4, 4, 98 +; AIX32-NEXT: mr 3, 4 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: add 3, 3, 31 +; AIX32-NEXT: lwz 31, 60(1) # 4-byte Folded Reload +; AIX32-NEXT: addi 1, 1, 64 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: str7: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -128(1) +; AIX64-NEXT: ld 3, L..C2(2) # @GLOBALSTRING +; AIX64-NEXT: std 0, 144(1) +; AIX64-NEXT: std 31, 120(1) # 8-byte Folded Spill +; AIX64-NEXT: ld 3, 0(3) +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: mr 31, 3 +; AIX64-NEXT: ld 3, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: addi 3, 3, 98 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: add 3, 3, 31 +; AIX64-NEXT: ld 31, 120(1) # 8-byte Folded Reload +; AIX64-NEXT: extsw 3, 3 +; AIX64-NEXT: addi 1, 1, 128 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: str7: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -128(1) +; LINUX64BE-NEXT: std 0, 144(1) +; LINUX64BE-NEXT: addis 3, 2, GLOBALSTRING@toc@ha +; LINUX64BE-NEXT: std 30, 112(1) # 8-byte Folded Spill +; LINUX64BE-NEXT: ld 3, GLOBALSTRING@toc@l(3) +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: mr 30, 3 +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: addi 3, 3, 98 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: add 3, 3, 30 +; LINUX64BE-NEXT: ld 30, 112(1) # 8-byte Folded Reload +; LINUX64BE-NEXT: extsw 3, 3 +; LINUX64BE-NEXT: addi 1, 1, 128 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: str7: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: std 30, -16(1) # 8-byte Folded Spill +; LINUX64LE-NEXT: stdu 1, -48(1) +; LINUX64LE-NEXT: std 0, 64(1) +; LINUX64LE-NEXT: addis 3, 2, GLOBALSTRING@toc@ha +; LINUX64LE-NEXT: ld 3, GLOBALSTRING@toc@l(3) +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: mr 30, 3 +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: addi 3, 3, 98 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: add 3, 3, 30 +; LINUX64LE-NEXT: extsw 3, 3 +; LINUX64LE-NEXT: addi 1, 1, 48 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: ld 30, -16(1) # 8-byte Folded Reload +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %0 = load ptr, ptr @GLOBALSTRING, align 8 + %call = tail call signext i32 @callee(ptr noundef %0) + %call1 = tail call signext i32 @callee(ptr noundef nonnull @.str.8) + %add = add nsw i32 %call1, %call + ret i32 %add +} + +define dso_local signext i32 @mixed1() local_unnamed_addr #0 { +; AIX32-LABEL: mixed1: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -64(1) +; AIX32-NEXT: lwz 3, L..C3(2) # @IntArray2 +; AIX32-NEXT: stw 0, 72(1) +; AIX32-NEXT: stw 31, 60(1) # 4-byte Folded Spill +; AIX32-NEXT: bl .calleeInt[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: lwz 4, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: mr 31, 3 +; AIX32-NEXT: addi 4, 4, 40 +; AIX32-NEXT: mr 3, 4 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: add 3, 3, 31 +; AIX32-NEXT: lwz 31, 60(1) # 4-byte Folded Reload +; AIX32-NEXT: addi 1, 1, 64 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: mixed1: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -128(1) +; AIX64-NEXT: ld 3, L..C3(2) # @IntArray2 +; AIX64-NEXT: std 0, 144(1) +; AIX64-NEXT: std 31, 120(1) # 8-byte Folded Spill +; AIX64-NEXT: bl .calleeInt[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: mr 31, 3 +; AIX64-NEXT: ld 3, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: addi 3, 3, 40 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: add 3, 3, 31 +; AIX64-NEXT: ld 31, 120(1) # 8-byte Folded Reload +; AIX64-NEXT: extsw 3, 3 +; AIX64-NEXT: addi 1, 1, 128 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: mixed1: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -128(1) +; LINUX64BE-NEXT: addis 3, 2, IntArray2@toc@ha +; LINUX64BE-NEXT: std 0, 144(1) +; LINUX64BE-NEXT: std 30, 112(1) # 8-byte Folded Spill +; LINUX64BE-NEXT: addi 3, 3, IntArray2@toc@l +; LINUX64BE-NEXT: bl calleeInt +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: mr 30, 3 +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: addi 3, 3, 40 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: add 3, 3, 30 +; LINUX64BE-NEXT: ld 30, 112(1) # 8-byte Folded Reload +; LINUX64BE-NEXT: extsw 3, 3 +; LINUX64BE-NEXT: addi 1, 1, 128 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: mixed1: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: std 30, -16(1) # 8-byte Folded Spill +; LINUX64LE-NEXT: stdu 1, -48(1) +; LINUX64LE-NEXT: addis 3, 2, IntArray2@toc@ha +; LINUX64LE-NEXT: std 0, 64(1) +; LINUX64LE-NEXT: addi 3, 3, IntArray2@toc@l +; LINUX64LE-NEXT: bl calleeInt +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: mr 30, 3 +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: addi 3, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: addi 3, 3, 40 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: add 3, 3, 30 +; LINUX64LE-NEXT: extsw 3, 3 +; LINUX64LE-NEXT: addi 1, 1, 48 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: ld 30, -16(1) # 8-byte Folded Reload +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %call = tail call signext i32 @calleeInt(ptr noundef nonnull @IntArray2) + %call1 = tail call signext i32 @callee(ptr noundef nonnull @.str.6) + %add = add nsw i32 %call1, %call + ret i32 %add +} + +define dso_local signext i32 @mixed2() local_unnamed_addr #0 { +; AIX32-LABEL: mixed2: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: mflr 0 +; AIX32-NEXT: stwu 1, -112(1) +; AIX32-NEXT: stw 0, 120(1) +; AIX32-NEXT: stw 30, 104(1) # 4-byte Folded Spill +; AIX32-NEXT: lwz 30, L..C0(2) # @__ModuleStringPool +; AIX32-NEXT: li 4, 12 +; AIX32-NEXT: addi 3, 1, 64 +; AIX32-NEXT: mr 5, 3 +; AIX32-NEXT: stw 31, 108(1) # 4-byte Folded Spill +; AIX32-NEXT: rlwimi 5, 4, 0, 28, 29 +; AIX32-NEXT: lxvw4x 0, 30, 4 +; AIX32-NEXT: lxvw4x 1, 0, 30 +; AIX32-NEXT: stxvw4x 0, 0, 5 +; AIX32-NEXT: stxvw4x 1, 0, 3 +; AIX32-NEXT: bl .calleeInt[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: lwz 4, L..C3(2) # @IntArray2 +; AIX32-NEXT: mr 31, 3 +; AIX32-NEXT: mr 3, 4 +; AIX32-NEXT: bl .calleeInt[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 4, 30, 40 +; AIX32-NEXT: mr 5, 3 +; AIX32-NEXT: mr 3, 4 +; AIX32-NEXT: add 31, 5, 31 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: addi 4, 30, 113 +; AIX32-NEXT: mr 5, 3 +; AIX32-NEXT: mr 3, 4 +; AIX32-NEXT: add 31, 31, 5 +; AIX32-NEXT: bl .callee[PR] +; AIX32-NEXT: nop +; AIX32-NEXT: add 3, 31, 3 +; AIX32-NEXT: lwz 31, 108(1) # 4-byte Folded Reload +; AIX32-NEXT: lwz 30, 104(1) # 4-byte Folded Reload +; AIX32-NEXT: addi 1, 1, 112 +; AIX32-NEXT: lwz 0, 8(1) +; AIX32-NEXT: mtlr 0 +; AIX32-NEXT: blr +; +; AIX64-LABEL: mixed2: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mflr 0 +; AIX64-NEXT: stdu 1, -160(1) +; AIX64-NEXT: std 0, 176(1) +; AIX64-NEXT: std 30, 144(1) # 8-byte Folded Spill +; AIX64-NEXT: ld 30, L..C0(2) # @__ModuleStringPool +; AIX64-NEXT: li 3, 12 +; AIX64-NEXT: addi 4, 1, 124 +; AIX64-NEXT: std 31, 152(1) # 8-byte Folded Spill +; AIX64-NEXT: lxvw4x 0, 30, 3 +; AIX64-NEXT: lxvw4x 1, 0, 30 +; AIX64-NEXT: addi 3, 1, 112 +; AIX64-NEXT: stxvw4x 0, 0, 4 +; AIX64-NEXT: stxvw4x 1, 0, 3 +; AIX64-NEXT: bl .calleeInt[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: mr 31, 3 +; AIX64-NEXT: ld 3, L..C3(2) # @IntArray2 +; AIX64-NEXT: bl .calleeInt[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: addi 4, 30, 40 +; AIX64-NEXT: add 31, 3, 31 +; AIX64-NEXT: mr 3, 4 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: addi 4, 30, 113 +; AIX64-NEXT: add 31, 31, 3 +; AIX64-NEXT: mr 3, 4 +; AIX64-NEXT: bl .callee[PR] +; AIX64-NEXT: nop +; AIX64-NEXT: add 3, 31, 3 +; AIX64-NEXT: ld 31, 152(1) # 8-byte Folded Reload +; AIX64-NEXT: ld 30, 144(1) # 8-byte Folded Reload +; AIX64-NEXT: extsw 3, 3 +; AIX64-NEXT: addi 1, 1, 160 +; AIX64-NEXT: ld 0, 16(1) +; AIX64-NEXT: mtlr 0 +; AIX64-NEXT: blr +; +; LINUX64BE-LABEL: mixed2: +; LINUX64BE: # %bb.0: # %entry +; LINUX64BE-NEXT: mflr 0 +; LINUX64BE-NEXT: stdu 1, -176(1) +; LINUX64BE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64BE-NEXT: std 0, 192(1) +; LINUX64BE-NEXT: std 29, 152(1) # 8-byte Folded Spill +; LINUX64BE-NEXT: addi 4, 1, 124 +; LINUX64BE-NEXT: std 30, 160(1) # 8-byte Folded Spill +; LINUX64BE-NEXT: addi 29, 3, .L__ModuleStringPool@toc@l +; LINUX64BE-NEXT: li 3, 12 +; LINUX64BE-NEXT: lxvw4x 0, 29, 3 +; LINUX64BE-NEXT: addi 3, 1, 112 +; LINUX64BE-NEXT: lxvw4x 1, 0, 29 +; LINUX64BE-NEXT: stxvw4x 0, 0, 4 +; LINUX64BE-NEXT: stxvw4x 1, 0, 3 +; LINUX64BE-NEXT: bl calleeInt +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: mr 30, 3 +; LINUX64BE-NEXT: addis 3, 2, IntArray2@toc@ha +; LINUX64BE-NEXT: addi 3, 3, IntArray2@toc@l +; LINUX64BE-NEXT: bl calleeInt +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: addi 4, 29, 40 +; LINUX64BE-NEXT: add 30, 3, 30 +; LINUX64BE-NEXT: mr 3, 4 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: addi 4, 29, 113 +; LINUX64BE-NEXT: add 30, 30, 3 +; LINUX64BE-NEXT: mr 3, 4 +; LINUX64BE-NEXT: bl callee +; LINUX64BE-NEXT: nop +; LINUX64BE-NEXT: add 3, 30, 3 +; LINUX64BE-NEXT: ld 30, 160(1) # 8-byte Folded Reload +; LINUX64BE-NEXT: ld 29, 152(1) # 8-byte Folded Reload +; LINUX64BE-NEXT: extsw 3, 3 +; LINUX64BE-NEXT: addi 1, 1, 176 +; LINUX64BE-NEXT: ld 0, 16(1) +; LINUX64BE-NEXT: mtlr 0 +; LINUX64BE-NEXT: blr +; +; LINUX64LE-LABEL: mixed2: +; LINUX64LE: # %bb.0: # %entry +; LINUX64LE-NEXT: mflr 0 +; LINUX64LE-NEXT: std 29, -24(1) # 8-byte Folded Spill +; LINUX64LE-NEXT: std 30, -16(1) # 8-byte Folded Spill +; LINUX64LE-NEXT: stdu 1, -96(1) +; LINUX64LE-NEXT: addis 3, 2, .L__ModuleStringPool@toc@ha +; LINUX64LE-NEXT: addi 4, 1, 44 +; LINUX64LE-NEXT: std 0, 112(1) +; LINUX64LE-NEXT: addi 29, 3, .L__ModuleStringPool@toc@l +; LINUX64LE-NEXT: li 3, 12 +; LINUX64LE-NEXT: lxvd2x 0, 29, 3 +; LINUX64LE-NEXT: lxvd2x 1, 0, 29 +; LINUX64LE-NEXT: addi 3, 1, 32 +; LINUX64LE-NEXT: stxvd2x 0, 0, 4 +; LINUX64LE-NEXT: stxvd2x 1, 0, 3 +; LINUX64LE-NEXT: bl calleeInt +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: mr 30, 3 +; LINUX64LE-NEXT: addis 3, 2, IntArray2@toc@ha +; LINUX64LE-NEXT: addi 3, 3, IntArray2@toc@l +; LINUX64LE-NEXT: bl calleeInt +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: addi 4, 29, 40 +; LINUX64LE-NEXT: add 30, 3, 30 +; LINUX64LE-NEXT: mr 3, 4 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: addi 4, 29, 113 +; LINUX64LE-NEXT: add 30, 30, 3 +; LINUX64LE-NEXT: mr 3, 4 +; LINUX64LE-NEXT: bl callee +; LINUX64LE-NEXT: nop +; LINUX64LE-NEXT: add 3, 30, 3 +; LINUX64LE-NEXT: extsw 3, 3 +; LINUX64LE-NEXT: addi 1, 1, 96 +; LINUX64LE-NEXT: ld 0, 16(1) +; LINUX64LE-NEXT: ld 30, -16(1) # 8-byte Folded Reload +; LINUX64LE-NEXT: ld 29, -24(1) # 8-byte Folded Reload +; LINUX64LE-NEXT: mtlr 0 +; LINUX64LE-NEXT: blr +entry: + %IntArray = alloca [7 x i32], align 4 + call void @llvm.lifetime.start.p0(i64 28, ptr nonnull %IntArray) + call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(28) %IntArray, ptr noundef nonnull align 4 dereferenceable(28) @__const.mixed2.IntArray, i64 28, i1 false) + %call = call signext i32 @calleeInt(ptr noundef nonnull %IntArray) + %call1 = call signext i32 @calleeInt(ptr noundef nonnull @IntArray2) + %add = add nsw i32 %call1, %call + %call2 = call signext i32 @callee(ptr noundef nonnull @.str.6) + %add3 = add nsw i32 %add, %call2 + %call4 = call signext i32 @callee(ptr noundef nonnull @.str.7) + %add5 = add nsw i32 %add3, %call4 + call void @llvm.lifetime.end.p0(i64 28, ptr nonnull %IntArray) + ret i32 %add5 +} + +attributes #0 = { nounwind } + +; AIXDATA: .csect L..__ModuleStringPool[RO],2 +; AIXDATA: .align 4 # @__ModuleStringPool +; AIXDATA: .vbyte 4, 5 # 0x5 +; AIXDATA: .vbyte 4, 7 # 0x7 +; AIXDATA: .vbyte 4, 9 # 0x9 +; AIXDATA: .vbyte 4, 11 # 0xb +; AIXDATA: .vbyte 4, 17 # 0x11 +; AIXDATA: .vbyte 4, 1235 # 0x4d3 +; AIXDATA: .vbyte 4, 32 # 0x20 +; AIXDATA: .string "str2_STRING" +; AIXDATA: .string "MixedString" +; AIXDATA: .string "ABCABCABC" +; AIXDATA: .string "str1_STRING" +; AIXDATA: .string "str3_STRING" +; AIXDATA: .string "str4_STRING" +; AIXDATA: .byte 'S,'t,'a,'t,'i,'c,' ,'G,'l,'o,'b,'a,'l,0012,0000 +; AIXDATA: .string "Different String 01" +; AIXDATA: .string "longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_STRING" + +; LINUXDATA: .L__ModuleStringPool: +; LINUXDATA: .long 5 # 0x5 +; LINUXDATA: .long 7 # 0x7 +; LINUXDATA: .long 9 # 0x9 +; LINUXDATA: .long 11 # 0xb +; LINUXDATA: .long 17 # 0x11 +; LINUXDATA: .long 1235 # 0x4d3 +; LINUXDATA: .long 32 # 0x20 +; LINUXDATA: .asciz "str2_STRING" +; LINUXDATA: .asciz "MixedString" +; LINUXDATA: .asciz "ABCABCABC" +; LINUXDATA: .asciz "str1_STRING" +; LINUXDATA: .asciz "str3_STRING" +; LINUXDATA: .asciz "str4_STRING" +; LINUXDATA: .asciz "Static Global\n" +; LINUXDATA: .asciz "Different String 01" +; LINUXDATA: .asciz "longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_longerstr5_STRING"