Index: lib/Transforms/IPO/MergeFunctions.cpp =================================================================== --- lib/Transforms/IPO/MergeFunctions.cpp +++ lib/Transforms/IPO/MergeFunctions.cpp @@ -96,8 +96,10 @@ #include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" @@ -127,6 +129,12 @@ "'0' disables this check. Works only with '-debug' key."), cl::init(0), cl::Hidden); +static cl::opt + MergeFunctionsPDI("mergefunc-preserve-debug-info", cl::Hidden, + cl::init(false), + cl::desc("Preserve debug info in thunk when mergefunc " + "transformations are made.")); + namespace { class FunctionNode { @@ -215,6 +223,17 @@ /// Replace G with a thunk or an alias to F. Deletes G. void writeThunkOrAlias(Function *F, Function *G); + /// Fill PDIUnrelatedWL with instructions from the entry block that are + /// unrelated to parameter related debug info. + void filterInstsUnrelatedToPDI(BasicBlock *GEntryBlock, + std::vector &PDIUnrelatedWL); + + /// Erase the rest of the CFG (i.e. barring the entry block). + void eraseTail(Function *G); + + /// Erase the instructions in PDIUnrelatedWL + void eraseInstsUnrelatedToPDI(std::vector &PDIUnrelatedWL); + /// Replace G with a simple tail call to bitcast(F). Also replace direct uses /// of G with bitcast(F). Deletes G. void writeThunk(Function *F, Function *G); @@ -461,6 +480,152 @@ return Builder.CreateBitCast(V, DestTy); } +// Erase the instructions in PDIUnrelatedWL +void MergeFunctions::eraseInstsUnrelatedToPDI( + std::vector &PDIUnrelatedWL) { + + DEBUG(dbgs() << " Erasing instructions (in reverse order of appearance in " + "entry block) unrelated to parameter debug info from entry " + "block: {\n"); + while (!PDIUnrelatedWL.empty()) { + Instruction *I = PDIUnrelatedWL.back(); + DEBUG(dbgs() << " Deleting Instruction: "); + DEBUG(I->print(dbgs())); + DEBUG(dbgs() << "\n"); + I->eraseFromParent(); + PDIUnrelatedWL.pop_back(); + } + DEBUG(dbgs() << " } // Done erasing instructions unrelated to parameter " + "debug info from entry block. \n"); +} + +// Reduce G to its entry block. +void MergeFunctions::eraseTail(Function *G) { + + std::vector WorklistBB; + for (Function::iterator BBI = std::next(G->begin()), BBE = G->end(); + BBI != BBE; ++BBI) { + BBI->dropAllReferences(); + WorklistBB.push_back(&*BBI); + } + while (!WorklistBB.empty()) { + BasicBlock *BB = WorklistBB.back(); + BB->eraseFromParent(); + WorklistBB.pop_back(); + } +} + +// We are interested in the following instructions from the entry block as being +// related to parameter debug info: +// - @llvm.dbg.declare +// - stores from the incoming parameters to locations on the stack-frame +// - allocas that create these locations on the stack-frame +// - @llvm.dbg.value +// - the entry block's terminator +// The rest are unrelated to debug info for the parameters; fill up +// PDIUnrelatedWL with such instructions. +void MergeFunctions::filterInstsUnrelatedToPDI( + BasicBlock *GEntryBlock, std::vector &PDIUnrelatedWL) { + + std::set PDIRelated; + for (BasicBlock::iterator BI = GEntryBlock->begin(), BIE = GEntryBlock->end(); + BI != BIE; ++BI) { + if (auto *DVI = dyn_cast(&*BI)) { + DEBUG(dbgs() << " Deciding: "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + DILocalVariable *DILocVar = DVI->getVariable(); + if (DILocVar->isParameter()) { + DEBUG(dbgs() << " Include (parameter): "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + PDIRelated.insert(&*BI); + } else { + DEBUG(dbgs() << " Delete (!parameter): "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + } + } else if (auto *DDI = dyn_cast(&*BI)) { + DEBUG(dbgs() << " Deciding: "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + DILocalVariable *DILocVar = DDI->getVariable(); + if (DILocVar->isParameter()) { + DEBUG(dbgs() << " Parameter: "); + DEBUG(DILocVar->print(dbgs())); + AllocaInst *AI = dyn_cast_or_null(DDI->getAddress()); + if (AI) { + DEBUG(dbgs() << " Processing alloca users: "); + DEBUG(dbgs() << "\n"); + for (User *U : AI->users()) { + if (StoreInst *SI = dyn_cast(U)) { + if (Value *Arg = SI->getValueOperand()) { + if (dyn_cast(Arg)) { + DEBUG(dbgs() << " Include: "); + DEBUG(AI->print(dbgs())); + DEBUG(dbgs() << "\n"); + PDIRelated.insert(AI); + DEBUG(dbgs() << " Include (parameter): "); + DEBUG(SI->print(dbgs())); + DEBUG(dbgs() << "\n"); + PDIRelated.insert(SI); + DEBUG(dbgs() << " Include: "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + PDIRelated.insert(&*BI); + } else { + DEBUG(dbgs() << " Delete (!parameter): "); + DEBUG(SI->print(dbgs())); + DEBUG(dbgs() << "\n"); + } + } + } else { + DEBUG(dbgs() << " Defer: "); + DEBUG(U->print(dbgs())); + DEBUG(dbgs() << "\n"); + } + } + } else { + DEBUG(dbgs() << " Delete (alloca NULL): "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + } + } else { + DEBUG(dbgs() << " Delete (!parameter): "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + } + } else if (dyn_cast(BI) == GEntryBlock->getTerminator()) { + DEBUG(dbgs() << " Will Include Terminator: "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + PDIRelated.insert(&*BI); + } else { + DEBUG(dbgs() << " Defer: "); + DEBUG(BI->print(dbgs())); + DEBUG(dbgs() << "\n"); + } + } + DEBUG(dbgs() + << " Report parameter debug info related/related instructions: {\n"); + for (BasicBlock::iterator BI = GEntryBlock->begin(), BE = GEntryBlock->end(); + BI != BE; ++BI) { + + Instruction *I = &*BI; + if (PDIRelated.find(I) == PDIRelated.end()) { + DEBUG(dbgs() << " !PDIRelated: "); + DEBUG(I->print(dbgs())); + DEBUG(dbgs() << "\n"); + PDIUnrelatedWL.push_back(I); + } else { + DEBUG(dbgs() << " PDIRelated: "); + DEBUG(I->print(dbgs())); + DEBUG(dbgs() << "\n"); + } + } + DEBUG(dbgs() << " }\n"); +} + // Replace G with a simple tail call to bitcast(F). Also replace direct uses // of G with bitcast(F). Deletes G. void MergeFunctions::writeThunk(Function *F, Function *G) { @@ -476,36 +641,76 @@ return; } - Function *NewG = Function::Create(G->getFunctionType(), G->getLinkage(), "", - G->getParent()); - BasicBlock *BB = BasicBlock::Create(F->getContext(), "", NewG); - IRBuilder<> Builder(BB); + BasicBlock *GEntryBlock = nullptr; + std::vector PDIUnrelatedWL; + BasicBlock *BB = nullptr; + Function *NewG = nullptr; + if (MergeFunctionsPDI) { + DEBUG(dbgs() << "writeThunk: (MergeFunctionsPDI) Do not create a new " + "function as thunk; retain original: " + << G->getName() << "()\n"); + GEntryBlock = &G->getEntryBlock(); + DEBUG(dbgs() << "writeThunk: (MergeFunctionsPDI) filter parameter related " + "debug info for " + << G->getName() << "() {\n"); + filterInstsUnrelatedToPDI(GEntryBlock, PDIUnrelatedWL); + GEntryBlock->getTerminator()->eraseFromParent(); + BB = GEntryBlock; + } else { + NewG = Function::Create(G->getFunctionType(), G->getLinkage(), "", + G->getParent()); + BB = BasicBlock::Create(F->getContext(), "", NewG); + } + IRBuilder<> Builder(BB); + Function *H = MergeFunctionsPDI ? G : NewG; SmallVector Args; unsigned i = 0; FunctionType *FFTy = F->getFunctionType(); - for (Argument & AI : NewG->args()) { + for (Argument & AI : H->args()) { Args.push_back(createCast(Builder, &AI, FFTy->getParamType(i))); ++i; } CallInst *CI = Builder.CreateCall(F, Args); - CI->setTailCall(); + ReturnInst *RI = nullptr; + // Note: (MergeFunctionsPDI) Not marking the call to F as a tail-call + // here will ensure that at -O0, we see the thunk G, make a + // call to F in back-traces. + if (!MergeFunctionsPDI) + CI->setTailCall(); CI->setCallingConv(F->getCallingConv()); CI->setAttributes(F->getAttributes()); - if (NewG->getReturnType()->isVoidTy()) { - Builder.CreateRetVoid(); + if (H->getReturnType()->isVoidTy()) { + RI = Builder.CreateRetVoid(); } else { - Builder.CreateRet(createCast(Builder, CI, NewG->getReturnType())); + RI = Builder.CreateRet(createCast(Builder, CI, H->getReturnType())); } - NewG->copyAttributesFrom(G); - NewG->takeName(G); - removeUsers(G); - G->replaceAllUsesWith(NewG); - G->eraseFromParent(); + if (MergeFunctionsPDI) { + DISubprogram *DIS = G->getSubprogram(); + if (DIS != nullptr) { + DebugLoc CIDbgLoc = DebugLoc::get(DIS->getScopeLine(), 0, DIS); + DebugLoc RIDbgLoc = DebugLoc::get(DIS->getScopeLine(), 0, DIS); + CI->setDebugLoc(CIDbgLoc); + RI->setDebugLoc(RIDbgLoc); + } else { + DEBUG(dbgs() << "writeThunk: (MergeFunctionsPDI) No DISubprogram for " + << G->getName() << "() {\n"); + } + eraseTail(G); + eraseInstsUnrelatedToPDI(PDIUnrelatedWL); + DEBUG(dbgs() << "} // End of parameter related debug info filtering for: " + << G->getName() << "()\n"); + } else { + NewG->copyAttributesFrom(G); + NewG->takeName(G); + removeUsers(G); + G->replaceAllUsesWith(NewG); + G->eraseFromParent(); + } - DEBUG(dbgs() << "writeThunk: " << NewG->getName() << '\n'); + DEBUG(dbgs() << "writeThunk: " << H->getName() << '\n'); ++NumThunksWritten; } Index: test/Transforms/MergeFunc/thunk-debugability.ll =================================================================== --- /dev/null +++ test/Transforms/MergeFunc/thunk-debugability.ll @@ -0,0 +1,489 @@ +; RUN: opt -O0 -S -mergefunc -mergefunc-preserve-debug-info < %s | FileCheck %s --check-prefix=OPTIMIZATION_LEVEL_0 +; RUN: opt -O2 -S -mergefunc -mergefunc-preserve-debug-info < %s | FileCheck %s --check-prefix=OPTIMIZATION_LEVEL_2 + +; Preserve debug info in thunks. +; What we test for: +; That, at -O0 we have retained the generated @llvm.dbg.declare debug intrinsics +; That, at -O2 we have retained the generated @llvm.dbg.value debug intrinsics +; In addition, that at -O0, stores from the incoming parameters to locations on the stack-frame +; and allocas that create these locations on the stack-frame are retained. +; Also, that debug info got generated for the call made by the thunk and for its return value. + +; The source code that was used to test and generate this LLVM IR appears at the end of this file. + +; ModuleID = './thunk-debugability.bc' +source_filename = "./thunk-debugability.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@main.a = private unnamed_addr constant [8 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8], align 16 +@main.b = private unnamed_addr constant [8 x i32] [i32 8, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1], align 16 + +; Function Attrs: nounwind uwtable +define i32 @dotSumA(i32* %r, i32* %p, i32* %q, i32 %size) #0 !dbg !6 { +entry: + %r.addr = alloca i32*, align 8 + %p.addr = alloca i32*, align 8 + %q.addr = alloca i32*, align 8 + %size.addr = alloca i32, align 4 + %i = alloca i32, align 4 + %s = alloca i32, align 4 + store i32* %r, i32** %r.addr, align 8 + call void @llvm.dbg.declare(metadata i32** %r.addr, metadata !12, metadata !13), !dbg !14 + store i32* %p, i32** %p.addr, align 8 + call void @llvm.dbg.declare(metadata i32** %p.addr, metadata !15, metadata !13), !dbg !16 + store i32* %q, i32** %q.addr, align 8 + call void @llvm.dbg.declare(metadata i32** %q.addr, metadata !17, metadata !13), !dbg !18 + store i32 %size, i32* %size.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %size.addr, metadata !19, metadata !13), !dbg !20 + call void @llvm.dbg.declare(metadata i32* %i, metadata !21, metadata !13), !dbg !22 + call void @llvm.dbg.declare(metadata i32* %s, metadata !23, metadata !13), !dbg !24 + store i32 0, i32* %i, align 4, !dbg !25 + br label %for.cond, !dbg !27 + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4, !dbg !28 + %1 = load i32, i32* %size.addr, align 4, !dbg !31 + %cmp = icmp slt i32 %0, %1, !dbg !32 + br i1 %cmp, label %for.body, label %for.end, !dbg !33 + +for.body: ; preds = %for.cond + %2 = load i32*, i32** %p.addr, align 8, !dbg !35 + %3 = load i32, i32* %i, align 4, !dbg !37 + %idxprom = sext i32 %3 to i64, !dbg !35 + %arrayidx = getelementptr inbounds i32, i32* %2, i64 %idxprom, !dbg !35 + %4 = load i32, i32* %arrayidx, align 4, !dbg !35 + %5 = load i32*, i32** %q.addr, align 8, !dbg !38 + %6 = load i32, i32* %i, align 4, !dbg !39 + %idxprom1 = sext i32 %6 to i64, !dbg !38 + %arrayidx2 = getelementptr inbounds i32, i32* %5, i64 %idxprom1, !dbg !38 + %7 = load i32, i32* %arrayidx2, align 4, !dbg !38 + %mul = mul nsw i32 %4, %7, !dbg !40 + %8 = load i32*, i32** %r.addr, align 8, !dbg !41 + %9 = load i32, i32* %i, align 4, !dbg !42 + %idxprom3 = sext i32 %9 to i64, !dbg !41 + %arrayidx4 = getelementptr inbounds i32, i32* %8, i64 %idxprom3, !dbg !41 + store i32 %mul, i32* %arrayidx4, align 4, !dbg !43 + br label %for.inc, !dbg !44 + +for.inc: ; preds = %for.body + %10 = load i32, i32* %i, align 4, !dbg !45 + %inc = add nsw i32 %10, 1, !dbg !45 + store i32 %inc, i32* %i, align 4, !dbg !45 + br label %for.cond, !dbg !47, !llvm.loop !48 + +for.end: ; preds = %for.cond + store i32 0, i32* %i, align 4, !dbg !51 + store i32 0, i32* %s, align 4, !dbg !53 + br label %for.cond5, !dbg !54 + +for.cond5: ; preds = %for.inc10, %for.end + %11 = load i32, i32* %i, align 4, !dbg !55 + %12 = load i32, i32* %size.addr, align 4, !dbg !58 + %cmp6 = icmp slt i32 %11, %12, !dbg !59 + br i1 %cmp6, label %for.body7, label %for.end12, !dbg !60 + +for.body7: ; preds = %for.cond5 + %13 = load i32*, i32** %r.addr, align 8, !dbg !62 + %14 = load i32, i32* %i, align 4, !dbg !63 + %idxprom8 = sext i32 %14 to i64, !dbg !62 + %arrayidx9 = getelementptr inbounds i32, i32* %13, i64 %idxprom8, !dbg !62 + %15 = load i32, i32* %arrayidx9, align 4, !dbg !62 + %16 = load i32, i32* %s, align 4, !dbg !64 + %add = add nsw i32 %16, %15, !dbg !64 + store i32 %add, i32* %s, align 4, !dbg !64 + br label %for.inc10, !dbg !65 + +for.inc10: ; preds = %for.body7 + %17 = load i32, i32* %i, align 4, !dbg !66 + %inc11 = add nsw i32 %17, 1, !dbg !66 + store i32 %inc11, i32* %i, align 4, !dbg !66 + br label %for.cond5, !dbg !68, !llvm.loop !69 + +for.end12: ; preds = %for.cond5 + %18 = load i32, i32* %s, align 4, !dbg !72 + ret i32 %18, !dbg !73 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind uwtable +define i32 @dotSumB(i32* %r, i32* %p, i32* %q, i32 %size) #0 !dbg !74 { + +; CHECK-LABEL: define i32 @dotSumB(i32* %r, i32* %p, i32* %q, i32 %size) + +; OPTIMIZATION_LEVEL_0: entry: +; OPTIMIZATION_LEVEL_0: %r.addr = alloca i32*, align 8 +; OPTIMIZATION_LEVEL_0: %p.addr = alloca i32*, align 8 +; OPTIMIZATION_LEVEL_0: %q.addr = alloca i32*, align 8 +; OPTIMIZATION_LEVEL_0: %size.addr = alloca i32, align 4 +; OPTIMIZATION_LEVEL_0: store i32* %r, i32** %r.addr, align 8 +; OPTIMIZATION_LEVEL_0: call void @llvm.dbg.declare(metadata i32** %r.addr, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_0: store i32* %p, i32** %p.addr, align 8 +; OPTIMIZATION_LEVEL_0: call void @llvm.dbg.declare(metadata i32** %p.addr, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_0: store i32* %q, i32** %q.addr, align 8 +; OPTIMIZATION_LEVEL_0: call void @llvm.dbg.declare(metadata i32** %q.addr, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_0: store i32 %size, i32* %size.addr, align 4 +; OPTIMIZATION_LEVEL_0: call void @llvm.dbg.declare(metadata i32* %size.addr, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_0: %0 = call i32 @dotSumA(i32* %r, i32* %p, i32* %q, i32 %size) #{{[0-9]+}}, !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_0: ret i32 %0, !dbg !{{[0-9]+}} + +; OPTIMIZATION_LEVEL_2: entry: +; OPTIMIZATION_LEVEL_2: tail call void @llvm.dbg.value(metadata i32* %r, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_2: tail call void @llvm.dbg.value(metadata i32* %p, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_2: tail call void @llvm.dbg.value(metadata i32* %q, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_2: tail call void @llvm.dbg.value(metadata i32 %size, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_2: %0 = call i32 @dotSumA(i32* nocapture %r, i32* nocapture readonly %p, i32* nocapture readonly %q, i32 %size) #0, !dbg !{{[0-9]+}} +; OPTIMIZATION_LEVEL_2: ret i32 %0, !dbg !{{[0-9]+}} + +entry: + %r.addr = alloca i32*, align 8 + %p.addr = alloca i32*, align 8 + %q.addr = alloca i32*, align 8 + %size.addr = alloca i32, align 4 + %i = alloca i32, align 4 + %s = alloca i32, align 4 + store i32* %r, i32** %r.addr, align 8 + call void @llvm.dbg.declare(metadata i32** %r.addr, metadata !75, metadata !13), !dbg !76 + store i32* %p, i32** %p.addr, align 8 + call void @llvm.dbg.declare(metadata i32** %p.addr, metadata !77, metadata !13), !dbg !78 + store i32* %q, i32** %q.addr, align 8 + call void @llvm.dbg.declare(metadata i32** %q.addr, metadata !79, metadata !13), !dbg !80 + store i32 %size, i32* %size.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %size.addr, metadata !81, metadata !13), !dbg !82 + call void @llvm.dbg.declare(metadata i32* %i, metadata !83, metadata !13), !dbg !84 + call void @llvm.dbg.declare(metadata i32* %s, metadata !85, metadata !13), !dbg !86 + store i32 0, i32* %i, align 4, !dbg !87 + br label %for.cond, !dbg !89 + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4, !dbg !90 + %1 = load i32, i32* %size.addr, align 4, !dbg !93 + %cmp = icmp slt i32 %0, %1, !dbg !94 + br i1 %cmp, label %for.body, label %for.end, !dbg !95 + +for.body: ; preds = %for.cond + %2 = load i32*, i32** %p.addr, align 8, !dbg !97 + %3 = load i32, i32* %i, align 4, !dbg !99 + %idxprom = sext i32 %3 to i64, !dbg !97 + %arrayidx = getelementptr inbounds i32, i32* %2, i64 %idxprom, !dbg !97 + %4 = load i32, i32* %arrayidx, align 4, !dbg !97 + %5 = load i32*, i32** %q.addr, align 8, !dbg !100 + %6 = load i32, i32* %i, align 4, !dbg !101 + %idxprom1 = sext i32 %6 to i64, !dbg !100 + %arrayidx2 = getelementptr inbounds i32, i32* %5, i64 %idxprom1, !dbg !100 + %7 = load i32, i32* %arrayidx2, align 4, !dbg !100 + %mul = mul nsw i32 %4, %7, !dbg !102 + %8 = load i32*, i32** %r.addr, align 8, !dbg !103 + %9 = load i32, i32* %i, align 4, !dbg !104 + %idxprom3 = sext i32 %9 to i64, !dbg !103 + %arrayidx4 = getelementptr inbounds i32, i32* %8, i64 %idxprom3, !dbg !103 + store i32 %mul, i32* %arrayidx4, align 4, !dbg !105 + br label %for.inc, !dbg !106 + +for.inc: ; preds = %for.body + %10 = load i32, i32* %i, align 4, !dbg !107 + %inc = add nsw i32 %10, 1, !dbg !107 + store i32 %inc, i32* %i, align 4, !dbg !107 + br label %for.cond, !dbg !109, !llvm.loop !110 + +for.end: ; preds = %for.cond + store i32 0, i32* %i, align 4, !dbg !113 + store i32 0, i32* %s, align 4, !dbg !115 + br label %for.cond5, !dbg !116 + +for.cond5: ; preds = %for.inc10, %for.end + %11 = load i32, i32* %i, align 4, !dbg !117 + %12 = load i32, i32* %size.addr, align 4, !dbg !120 + %cmp6 = icmp slt i32 %11, %12, !dbg !121 + br i1 %cmp6, label %for.body7, label %for.end12, !dbg !122 + +for.body7: ; preds = %for.cond5 + %13 = load i32*, i32** %r.addr, align 8, !dbg !124 + %14 = load i32, i32* %i, align 4, !dbg !125 + %idxprom8 = sext i32 %14 to i64, !dbg !124 + %arrayidx9 = getelementptr inbounds i32, i32* %13, i64 %idxprom8, !dbg !124 + %15 = load i32, i32* %arrayidx9, align 4, !dbg !124 + %16 = load i32, i32* %s, align 4, !dbg !126 + %add = add nsw i32 %16, %15, !dbg !126 + store i32 %add, i32* %s, align 4, !dbg !126 + br label %for.inc10, !dbg !127 + +for.inc10: ; preds = %for.body7 + %17 = load i32, i32* %i, align 4, !dbg !128 + %inc11 = add nsw i32 %17, 1, !dbg !128 + store i32 %inc11, i32* %i, align 4, !dbg !128 + br label %for.cond5, !dbg !130, !llvm.loop !131 + +for.end12: ; preds = %for.cond5 + %18 = load i32, i32* %s, align 4, !dbg !134 + ret i32 %18, !dbg !135 +} + +; Function Attrs: nounwind uwtable +define i32 @main() #0 !dbg !136 { +entry: + %retval = alloca i32, align 4 + %a = alloca [8 x i32], align 16 + %b = alloca [8 x i32], align 16 + %c = alloca [8 x i32], align 16 + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + call void @llvm.dbg.declare(metadata [8 x i32]* %a, metadata !139, metadata !13), !dbg !143 + %0 = bitcast [8 x i32]* %a to i8*, !dbg !143 + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* bitcast ([8 x i32]* @main.a to i8*), i64 32, i32 16, i1 false), !dbg !143 + call void @llvm.dbg.declare(metadata [8 x i32]* %b, metadata !144, metadata !13), !dbg !145 + %1 = bitcast [8 x i32]* %b to i8*, !dbg !145 + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast ([8 x i32]* @main.b to i8*), i64 32, i32 16, i1 false), !dbg !145 + call void @llvm.dbg.declare(metadata [8 x i32]* %c, metadata !146, metadata !13), !dbg !147 + call void @llvm.dbg.declare(metadata i32* %x, metadata !148, metadata !13), !dbg !149 + call void @llvm.dbg.declare(metadata i32* %y, metadata !150, metadata !13), !dbg !151 + call void @llvm.dbg.declare(metadata i32* %z, metadata !152, metadata !13), !dbg !153 + %arraydecay = getelementptr inbounds [8 x i32], [8 x i32]* %c, i32 0, i32 0, !dbg !154 + %arraydecay1 = getelementptr inbounds [8 x i32], [8 x i32]* %a, i32 0, i32 0, !dbg !155 + %arraydecay2 = getelementptr inbounds [8 x i32], [8 x i32]* %b, i32 0, i32 0, !dbg !156 + %call = call i32 @dotSumA(i32* %arraydecay, i32* %arraydecay1, i32* %arraydecay2, i32 8), !dbg !157 + store i32 %call, i32* %x, align 4, !dbg !158 + %arraydecay3 = getelementptr inbounds [8 x i32], [8 x i32]* %c, i32 0, i32 0, !dbg !159 + %arraydecay4 = getelementptr inbounds [8 x i32], [8 x i32]* %a, i32 0, i32 0, !dbg !160 + %arraydecay5 = getelementptr inbounds [8 x i32], [8 x i32]* %b, i32 0, i32 0, !dbg !161 + %call6 = call i32 @dotSumB(i32* %arraydecay3, i32* %arraydecay4, i32* %arraydecay5, i32 8), !dbg !162 + store i32 %call6, i32* %y, align 4, !dbg !163 + ret i32 0, !dbg !164 +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #2 + +attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { argmemonly nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (http://llvm.org/git/clang.git 5cc8e8e46cffb91599efc751efa20c6bdf350884) (http://llvm.org/git/llvm.git eaf3712d06ee4d2eb53e908cdc6d08365adb7b08)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "thunk-debugability.c", directory: "/auto/compiler-migration/anmparal/code/upstreaming/MFI") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 5cc8e8e46cffb91599efc751efa20c6bdf350884) (http://llvm.org/git/llvm.git eaf3712d06ee4d2eb53e908cdc6d08365adb7b08)"} +!6 = distinct !DISubprogram(name: "dotSumA", scope: !7, file: !7, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!7 = !DIFile(filename: "./thunk-debugability.c", directory: "/auto/compiler-migration/anmparal/code/upstreaming/MFI") +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11, !11, !11, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!12 = !DILocalVariable(name: "r", arg: 1, scope: !6, file: !7, line: 1, type: !11) +!13 = !DIExpression() +!14 = !DILocation(line: 1, column: 18, scope: !6) +!15 = !DILocalVariable(name: "p", arg: 2, scope: !6, file: !7, line: 1, type: !11) +!16 = !DILocation(line: 1, column: 26, scope: !6) +!17 = !DILocalVariable(name: "q", arg: 3, scope: !6, file: !7, line: 1, type: !11) +!18 = !DILocation(line: 1, column: 34, scope: !6) +!19 = !DILocalVariable(name: "size", arg: 4, scope: !6, file: !7, line: 1, type: !10) +!20 = !DILocation(line: 1, column: 41, scope: !6) +!21 = !DILocalVariable(name: "i", scope: !6, file: !7, line: 2, type: !10) +!22 = !DILocation(line: 2, column: 7, scope: !6) +!23 = !DILocalVariable(name: "s", scope: !6, file: !7, line: 2, type: !10) +!24 = !DILocation(line: 2, column: 10, scope: !6) +!25 = !DILocation(line: 3, column: 10, scope: !26) +!26 = distinct !DILexicalBlock(scope: !6, file: !7, line: 3, column: 3) +!27 = !DILocation(line: 3, column: 8, scope: !26) +!28 = !DILocation(line: 3, column: 15, scope: !29) +!29 = !DILexicalBlockFile(scope: !30, file: !7, discriminator: 1) +!30 = distinct !DILexicalBlock(scope: !26, file: !7, line: 3, column: 3) +!31 = !DILocation(line: 3, column: 19, scope: !29) +!32 = !DILocation(line: 3, column: 17, scope: !29) +!33 = !DILocation(line: 3, column: 3, scope: !34) +!34 = !DILexicalBlockFile(scope: !26, file: !7, discriminator: 1) +!35 = !DILocation(line: 4, column: 12, scope: !36) +!36 = distinct !DILexicalBlock(scope: !30, file: !7, line: 3, column: 30) +!37 = !DILocation(line: 4, column: 14, scope: !36) +!38 = !DILocation(line: 4, column: 19, scope: !36) +!39 = !DILocation(line: 4, column: 21, scope: !36) +!40 = !DILocation(line: 4, column: 17, scope: !36) +!41 = !DILocation(line: 4, column: 5, scope: !36) +!42 = !DILocation(line: 4, column: 7, scope: !36) +!43 = !DILocation(line: 4, column: 10, scope: !36) +!44 = !DILocation(line: 5, column: 3, scope: !36) +!45 = !DILocation(line: 3, column: 26, scope: !46) +!46 = !DILexicalBlockFile(scope: !30, file: !7, discriminator: 2) +!47 = !DILocation(line: 3, column: 3, scope: !46) +!48 = distinct !{!48, !49, !50} +!49 = !DILocation(line: 3, column: 3, scope: !26) +!50 = !DILocation(line: 5, column: 3, scope: !26) +!51 = !DILocation(line: 6, column: 10, scope: !52) +!52 = distinct !DILexicalBlock(scope: !6, file: !7, line: 6, column: 3) +!53 = !DILocation(line: 6, column: 17, scope: !52) +!54 = !DILocation(line: 6, column: 8, scope: !52) +!55 = !DILocation(line: 6, column: 22, scope: !56) +!56 = !DILexicalBlockFile(scope: !57, file: !7, discriminator: 1) +!57 = distinct !DILexicalBlock(scope: !52, file: !7, line: 6, column: 3) +!58 = !DILocation(line: 6, column: 26, scope: !56) +!59 = !DILocation(line: 6, column: 24, scope: !56) +!60 = !DILocation(line: 6, column: 3, scope: !61) +!61 = !DILexicalBlockFile(scope: !52, file: !7, discriminator: 1) +!62 = !DILocation(line: 7, column: 10, scope: !57) +!63 = !DILocation(line: 7, column: 12, scope: !57) +!64 = !DILocation(line: 7, column: 7, scope: !57) +!65 = !DILocation(line: 7, column: 5, scope: !57) +!66 = !DILocation(line: 6, column: 33, scope: !67) +!67 = !DILexicalBlockFile(scope: !57, file: !7, discriminator: 2) +!68 = !DILocation(line: 6, column: 3, scope: !67) +!69 = distinct !{!69, !70, !71} +!70 = !DILocation(line: 6, column: 3, scope: !52) +!71 = !DILocation(line: 7, column: 13, scope: !52) +!72 = !DILocation(line: 8, column: 10, scope: !6) +!73 = !DILocation(line: 8, column: 3, scope: !6) +!74 = distinct !DISubprogram(name: "dotSumB", scope: !7, file: !7, line: 11, type: !8, isLocal: false, isDefinition: true, scopeLine: 11, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!75 = !DILocalVariable(name: "r", arg: 1, scope: !74, file: !7, line: 11, type: !11) +!76 = !DILocation(line: 11, column: 18, scope: !74) +!77 = !DILocalVariable(name: "p", arg: 2, scope: !74, file: !7, line: 11, type: !11) +!78 = !DILocation(line: 11, column: 26, scope: !74) +!79 = !DILocalVariable(name: "q", arg: 3, scope: !74, file: !7, line: 11, type: !11) +!80 = !DILocation(line: 11, column: 34, scope: !74) +!81 = !DILocalVariable(name: "size", arg: 4, scope: !74, file: !7, line: 11, type: !10) +!82 = !DILocation(line: 11, column: 41, scope: !74) +!83 = !DILocalVariable(name: "i", scope: !74, file: !7, line: 13, type: !10) +!84 = !DILocation(line: 13, column: 7, scope: !74) +!85 = !DILocalVariable(name: "s", scope: !74, file: !7, line: 13, type: !10) +!86 = !DILocation(line: 13, column: 10, scope: !74) +!87 = !DILocation(line: 14, column: 10, scope: !88) +!88 = distinct !DILexicalBlock(scope: !74, file: !7, line: 14, column: 3) +!89 = !DILocation(line: 14, column: 8, scope: !88) +!90 = !DILocation(line: 14, column: 15, scope: !91) +!91 = !DILexicalBlockFile(scope: !92, file: !7, discriminator: 1) +!92 = distinct !DILexicalBlock(scope: !88, file: !7, line: 14, column: 3) +!93 = !DILocation(line: 14, column: 19, scope: !91) +!94 = !DILocation(line: 14, column: 17, scope: !91) +!95 = !DILocation(line: 14, column: 3, scope: !96) +!96 = !DILexicalBlockFile(scope: !88, file: !7, discriminator: 1) +!97 = !DILocation(line: 15, column: 12, scope: !98) +!98 = distinct !DILexicalBlock(scope: !92, file: !7, line: 14, column: 30) +!99 = !DILocation(line: 15, column: 14, scope: !98) +!100 = !DILocation(line: 15, column: 19, scope: !98) +!101 = !DILocation(line: 15, column: 21, scope: !98) +!102 = !DILocation(line: 15, column: 17, scope: !98) +!103 = !DILocation(line: 15, column: 5, scope: !98) +!104 = !DILocation(line: 15, column: 7, scope: !98) +!105 = !DILocation(line: 15, column: 10, scope: !98) +!106 = !DILocation(line: 16, column: 3, scope: !98) +!107 = !DILocation(line: 14, column: 26, scope: !108) +!108 = !DILexicalBlockFile(scope: !92, file: !7, discriminator: 2) +!109 = !DILocation(line: 14, column: 3, scope: !108) +!110 = distinct !{!110, !111, !112} +!111 = !DILocation(line: 14, column: 3, scope: !88) +!112 = !DILocation(line: 16, column: 3, scope: !88) +!113 = !DILocation(line: 17, column: 10, scope: !114) +!114 = distinct !DILexicalBlock(scope: !74, file: !7, line: 17, column: 3) +!115 = !DILocation(line: 17, column: 17, scope: !114) +!116 = !DILocation(line: 17, column: 8, scope: !114) +!117 = !DILocation(line: 17, column: 22, scope: !118) +!118 = !DILexicalBlockFile(scope: !119, file: !7, discriminator: 1) +!119 = distinct !DILexicalBlock(scope: !114, file: !7, line: 17, column: 3) +!120 = !DILocation(line: 17, column: 26, scope: !118) +!121 = !DILocation(line: 17, column: 24, scope: !118) +!122 = !DILocation(line: 17, column: 3, scope: !123) +!123 = !DILexicalBlockFile(scope: !114, file: !7, discriminator: 1) +!124 = !DILocation(line: 18, column: 10, scope: !119) +!125 = !DILocation(line: 18, column: 12, scope: !119) +!126 = !DILocation(line: 18, column: 7, scope: !119) +!127 = !DILocation(line: 18, column: 5, scope: !119) +!128 = !DILocation(line: 17, column: 33, scope: !129) +!129 = !DILexicalBlockFile(scope: !119, file: !7, discriminator: 2) +!130 = !DILocation(line: 17, column: 3, scope: !129) +!131 = distinct !{!131, !132, !133} +!132 = !DILocation(line: 17, column: 3, scope: !114) +!133 = !DILocation(line: 18, column: 13, scope: !114) +!134 = !DILocation(line: 19, column: 10, scope: !74) +!135 = !DILocation(line: 19, column: 3, scope: !74) +!136 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 24, type: !137, isLocal: false, isDefinition: true, scopeLine: 24, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!137 = !DISubroutineType(types: !138) +!138 = !{!10} +!139 = !DILocalVariable(name: "a", scope: !136, file: !7, line: 26, type: !140) +!140 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 256, elements: !141) +!141 = !{!142} +!142 = !DISubrange(count: 8) +!143 = !DILocation(line: 26, column: 7, scope: !136) +!144 = !DILocalVariable(name: "b", scope: !136, file: !7, line: 27, type: !140) +!145 = !DILocation(line: 27, column: 7, scope: !136) +!146 = !DILocalVariable(name: "c", scope: !136, file: !7, line: 28, type: !140) +!147 = !DILocation(line: 28, column: 7, scope: !136) +!148 = !DILocalVariable(name: "x", scope: !136, file: !7, line: 30, type: !10) +!149 = !DILocation(line: 30, column: 7, scope: !136) +!150 = !DILocalVariable(name: "y", scope: !136, file: !7, line: 30, type: !10) +!151 = !DILocation(line: 30, column: 10, scope: !136) +!152 = !DILocalVariable(name: "z", scope: !136, file: !7, line: 30, type: !10) +!153 = !DILocation(line: 30, column: 13, scope: !136) +!154 = !DILocation(line: 32, column: 15, scope: !136) +!155 = !DILocation(line: 32, column: 18, scope: !136) +!156 = !DILocation(line: 32, column: 21, scope: !136) +!157 = !DILocation(line: 32, column: 7, scope: !136) +!158 = !DILocation(line: 32, column: 5, scope: !136) +!159 = !DILocation(line: 33, column: 15, scope: !136) +!160 = !DILocation(line: 33, column: 18, scope: !136) +!161 = !DILocation(line: 33, column: 21, scope: !136) +!162 = !DILocation(line: 33, column: 7, scope: !136) +!163 = !DILocation(line: 33, column: 5, scope: !136) +!164 = !DILocation(line: 37, column: 3, scope: !136) + +; thunk-debugability.c: +; +; int dotSumA(int *r, int *p, int *q, int size) { +; int i, s; +; for (i = 0; i < size; i++) { +; r[i] = p[i] * q[i]; +; } +; for (i = 0, s = 0; i < size; i++) +; s += r[i]; +; return s; +; } +; +; int dotSumB(int *r, int *p, int *q, int size) { +; +; int i, s; +; for (i = 0; i < size; i++) { +; r[i] = p[i] * q[i]; +; } +; for (i = 0, s = 0; i < size; i++) +; s += r[i]; +; return s; +; } +; +; extern int dotSumExternalTest(int *r, int *p, int *q, int size); +; +; int main(void) { +; +; int a[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; +; int b[8] = { 8, 7, 6, 5, 4, 3, 2, 1 }; +; int c[8]; +; +; int x, y, z; +; +; x = dotSumA(c, a, b, 8); +; y = dotSumB(c, a, b, 8); +; +; // z = dotSumExternalTest (c, a, b, 8); +; +; return 0; +; } + +; thunk-debugability-aux.c +; +; extern int dotSumA(int *r, int *p, int *q, int size); +; extern int dotSumB(int *r, int *p, int *q, int size); +; +; int dotSumExternalTest(int *r, int *p, int *q, int size) { +; +; int x, y; +; +; x = dotSumA(r, p, q, 8); +; y = dotSumB(r, p, q, 8); +; +; return (x == y); +; }