summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/IRBuilder.h17
-rw-r--r--llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp221
-rw-r--r--llvm/test/Transforms/GCOVProfiling/function-numbering.ll69
3 files changed, 263 insertions, 44 deletions
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 278c5c5c763..cc37c3a1841 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -1476,14 +1476,19 @@ public:
return CreateConstInBoundsGEP2_32(Ty, Ptr, 0, Idx, Name);
}
+ Value *CreateStructGEP(Value *Ptr, unsigned Idx, const Twine &Name = "") {
+ return CreateConstInBoundsGEP2_32(nullptr, Ptr, 0, Idx, Name);
+ }
+
/// Same as CreateGlobalString, but return a pointer with "i8*" type
/// instead of a pointer to array of i8.
- Value *CreateGlobalStringPtr(StringRef Str, const Twine &Name = "",
- unsigned AddressSpace = 0) {
- GlobalVariable *gv = CreateGlobalString(Str, Name, AddressSpace);
- Value *zero = ConstantInt::get(Type::getInt32Ty(Context), 0);
- Value *Args[] = { zero, zero };
- return CreateInBoundsGEP(gv->getValueType(), gv, Args, Name);
+ Constant *CreateGlobalStringPtr(StringRef Str, const Twine &Name = "",
+ unsigned AddressSpace = 0) {
+ GlobalVariable *GV = CreateGlobalString(Str, Name, AddressSpace);
+ Constant *Zero = ConstantInt::get(Type::getInt32Ty(Context), 0);
+ Constant *Indices[] = {Zero, Zero};
+ return ConstantExpr::getInBoundsGetElementPtr(GV->getValueType(), GV,
+ Indices);
}
//===--------------------------------------------------------------------===//
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index 44bb67902c8..7447cb8c23c 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -17,6 +17,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
@@ -35,8 +36,8 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <algorithm>
#include <memory>
@@ -886,46 +887,196 @@ Function *GCOVProfiler::insertCounterWriteout(
Constant *SummaryInfo = getSummaryInfoFunc();
Constant *EndFile = getEndFileFunc();
- NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu");
- if (CU_Nodes) {
- for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
- auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i));
+ NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu");
+ if (!CUNodes) {
+ Builder.CreateRetVoid();
+ return WriteoutF;
+ }
- // Skip module skeleton (and module) CUs.
- if (CU->getDWOId())
- continue;
+ // Collect the relevant data into a large constant data structure that we can
+ // walk to write out everything.
+ StructType *StartFileCallArgsTy = StructType::create(
+ {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()});
+ StructType *EmitFunctionCallArgsTy = StructType::create(
+ {Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(),
+ Builder.getInt8Ty(), Builder.getInt32Ty()});
+ StructType *EmitArcsCallArgsTy = StructType::create(
+ {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()});
+ StructType *FileInfoTy =
+ StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(),
+ EmitFunctionCallArgsTy->getPointerTo(),
+ EmitArcsCallArgsTy->getPointerTo()});
+
+ Constant *Zero32 = Builder.getInt32(0);
+
+ SmallVector<Constant *, 8> FileInfos;
+ for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) {
+ auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i));
- std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);
- uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];
- Builder.CreateCall(StartFile,
- {Builder.CreateGlobalStringPtr(FilenameGcda),
- Builder.CreateGlobalStringPtr(ReversedVersion),
- Builder.getInt32(CfgChecksum)});
- for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) {
- auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second);
- uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();
- Builder.CreateCall(
- EmitFunction,
- {Builder.getInt32(j),
- Options.FunctionNamesInData
- ? Builder.CreateGlobalStringPtr(getFunctionName(SP))
- : Constant::getNullValue(Builder.getInt8PtrTy()),
- Builder.getInt32(FuncChecksum),
- Builder.getInt8(Options.UseCfgChecksum),
- Builder.getInt32(CfgChecksum)});
-
- GlobalVariable *GV = CountersBySP[j].first;
- unsigned Arcs =
- cast<ArrayType>(GV->getValueType())->getNumElements();
- Builder.CreateCall(EmitArcs, {Builder.getInt32(Arcs),
- Builder.CreateConstGEP2_64(GV, 0, 0)});
- }
- Builder.CreateCall(SummaryInfo, {});
- Builder.CreateCall(EndFile, {});
+ // Skip module skeleton (and module) CUs.
+ if (CU->getDWOId())
+ continue;
+
+ std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);
+ uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];
+ auto *StartFileCallArgs = ConstantStruct::get(
+ StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda),
+ Builder.CreateGlobalStringPtr(ReversedVersion),
+ Builder.getInt32(CfgChecksum)});
+
+ SmallVector<Constant *, 8> EmitFunctionCallArgsArray;
+ SmallVector<Constant *, 8> EmitArcsCallArgsArray;
+ for (int j : llvm::seq<int>(0, CountersBySP.size())) {
+ auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second);
+ uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();
+ EmitFunctionCallArgsArray.push_back(ConstantStruct::get(
+ EmitFunctionCallArgsTy,
+ {Builder.getInt32(j),
+ Options.FunctionNamesInData
+ ? Builder.CreateGlobalStringPtr(getFunctionName(SP))
+ : Constant::getNullValue(Builder.getInt8PtrTy()),
+ Builder.getInt32(FuncChecksum),
+ Builder.getInt8(Options.UseCfgChecksum),
+ Builder.getInt32(CfgChecksum)}));
+
+ GlobalVariable *GV = CountersBySP[j].first;
+ unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements();
+ EmitArcsCallArgsArray.push_back(ConstantStruct::get(
+ EmitArcsCallArgsTy,
+ {Builder.getInt32(Arcs),
+ ConstantExpr::getInBoundsGetElementPtr(
+ GV->getValueType(), GV,
+ makeArrayRef<Constant *>({Zero32, Zero32}))}));
}
+ // Create global arrays for the two emit calls.
+ int CountersSize = CountersBySP.size();
+ assert(CountersSize == (int)EmitFunctionCallArgsArray.size() &&
+ "Mismatched array size!");
+ assert(CountersSize == (int)EmitArcsCallArgsArray.size() &&
+ "Mismatched array size!");
+ auto *EmitFunctionCallArgsArrayTy =
+ ArrayType::get(EmitFunctionCallArgsTy, CountersSize);
+ auto *EmitFunctionCallArgsArrayGV = new GlobalVariable(
+ *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true,
+ GlobalValue::InternalLinkage,
+ ConstantArray::get(EmitFunctionCallArgsArrayTy,
+ EmitFunctionCallArgsArray),
+ Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i));
+ auto *EmitArcsCallArgsArrayTy =
+ ArrayType::get(EmitArcsCallArgsTy, CountersSize);
+ EmitFunctionCallArgsArrayGV->setUnnamedAddr(
+ GlobalValue::UnnamedAddr::Global);
+ auto *EmitArcsCallArgsArrayGV = new GlobalVariable(
+ *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true,
+ GlobalValue::InternalLinkage,
+ ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray),
+ Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i));
+ EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+
+ FileInfos.push_back(ConstantStruct::get(
+ FileInfoTy,
+ {StartFileCallArgs, Builder.getInt32(CountersSize),
+ ConstantExpr::getInBoundsGetElementPtr(
+ EmitFunctionCallArgsArrayTy, EmitFunctionCallArgsArrayGV,
+ makeArrayRef<Constant *>({Zero32, Zero32})),
+ ConstantExpr::getInBoundsGetElementPtr(
+ EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV,
+ makeArrayRef<Constant *>({Zero32, Zero32}))}));
}
+ // If we didn't find anything to actually emit, bail on out.
+ if (FileInfos.empty()) {
+ Builder.CreateRetVoid();
+ return WriteoutF;
+ }
+
+ // To simplify code, we cap the number of file infos we write out to fit
+ // easily in a 32-bit signed integer. This gives consistent behavior between
+ // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit
+ // operations on 32-bit systems. It also seems unreasonable to try to handle
+ // more than 2 billion files.
+ if ((int64_t)FileInfos.size() > (int64_t)INT_MAX)
+ FileInfos.resize(INT_MAX);
+
+ // Create a global for the entire data structure so we can walk it more
+ // easily.
+ auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size());
+ auto *FileInfoArrayGV = new GlobalVariable(
+ *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage,
+ ConstantArray::get(FileInfoArrayTy, FileInfos),
+ "__llvm_internal_gcov_emit_file_info");
+ FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+
+ // Create the CFG for walking this data structure.
+ auto *FileLoopHeader =
+ BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF);
+ auto *CounterLoopHeader =
+ BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF);
+ auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF);
+ auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF);
+
+ // We always have at least one file, so just branch to the header.
+ Builder.CreateBr(FileLoopHeader);
+
+ // The index into the files structure is our loop induction variable.
+ Builder.SetInsertPoint(FileLoopHeader);
+ PHINode *IV =
+ Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2);
+ IV->addIncoming(Builder.getInt32(0), BB);
+ auto *FileInfoPtr =
+ Builder.CreateInBoundsGEP(FileInfoArrayGV, {Builder.getInt32(0), IV});
+ auto *StartFileCallArgsPtr = Builder.CreateStructGEP(FileInfoPtr, 0);
+ Builder.CreateCall(
+ StartFile,
+ {Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 0)),
+ Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 1)),
+ Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 2))});
+ auto *NumCounters =
+ Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 1));
+ auto *EmitFunctionCallArgsArray =
+ Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 2));
+ auto *EmitArcsCallArgsArray =
+ Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 3));
+ auto *EnterCounterLoopCond =
+ Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters);
+ Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch);
+
+ Builder.SetInsertPoint(CounterLoopHeader);
+ auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2);
+ JV->addIncoming(Builder.getInt32(0), FileLoopHeader);
+ auto *EmitFunctionCallArgsPtr =
+ Builder.CreateInBoundsGEP(EmitFunctionCallArgsArray, {JV});
+ Builder.CreateCall(
+ EmitFunction,
+ {Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 0)),
+ Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 1)),
+ Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 2)),
+ Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 3)),
+ Builder.CreateLoad(
+ Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 4))});
+ auto *EmitArcsCallArgsPtr =
+ Builder.CreateInBoundsGEP(EmitArcsCallArgsArray, {JV});
+ Builder.CreateCall(
+ EmitArcs,
+ {Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 0)),
+ Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 1))});
+ auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1));
+ auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters);
+ Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch);
+ JV->addIncoming(NextJV, CounterLoopHeader);
+
+ Builder.SetInsertPoint(FileLoopLatch);
+ Builder.CreateCall(SummaryInfo, {});
+ Builder.CreateCall(EndFile, {});
+ auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1));
+ auto *FileLoopCond =
+ Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size()));
+ Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB);
+ IV->addIncoming(NextIV, FileLoopLatch);
+
+ Builder.SetInsertPoint(ExitBB);
Builder.CreateRetVoid();
+
return WriteoutF;
}
diff --git a/llvm/test/Transforms/GCOVProfiling/function-numbering.ll b/llvm/test/Transforms/GCOVProfiling/function-numbering.ll
index 4e8beb79c02..2acf6b49a79 100644
--- a/llvm/test/Transforms/GCOVProfiling/function-numbering.ll
+++ b/llvm/test/Transforms/GCOVProfiling/function-numbering.ll
@@ -19,9 +19,72 @@ target triple = "x86_64-apple-macosx10.10.0"
; GCDA: @[[FOO:[0-9]+]] = private unnamed_addr constant [4 x i8] c"foo\00"
; GCDA-NOT: @{{[0-9]+}} = private unnamed_addr constant .* c"bar\00"
; GCDA: @[[BAZ:[0-9]+]] = private unnamed_addr constant [4 x i8] c"baz\00"
-; GCDA: define internal void @__llvm_gcov_writeout()
-; GCDA: call void @llvm_gcda_emit_function(i32 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[FOO]]
-; GCDA: call void @llvm_gcda_emit_function(i32 1, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[BAZ]]
+; GCDA: @__llvm_internal_gcov_emit_function_args.0 = internal unnamed_addr constant
+; GCDA-SAME: { i32 0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[FOO]]
+; GCDA-SAME: { i32 1, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[BAZ]]
+;
+; GCDA-LABEL: define internal void @__llvm_gcov_writeout() {{.*}} {
+; GCDA-NEXT: entry:
+; GCDA-NEXT: br label %[[FILE_LOOP_HEADER:.*]]
+;
+; GCDA: [[FILE_LOOP_HEADER]]:
+; GCDA-NEXT: %[[IV:.*]] = phi i32 [ 0, %entry ], [ %[[NEXT_IV:.*]], %[[FILE_LOOP_LATCH:.*]] ]
+; GCDA-NEXT: %[[FILE_INFO:.*]] = getelementptr inbounds {{.*}}, {{.*}}* @__llvm_internal_gcov_emit_file_info, i32 0, i32 %[[IV]]
+; GCDA-NEXT: %[[START_FILE_ARGS:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[FILE_INFO]], i32 0, i32 0
+; GCDA-NEXT: %[[START_FILE_ARG_0_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[START_FILE_ARGS]], i32 0, i32 0
+; GCDA-NEXT: %[[START_FILE_ARG_0:.*]] = load i8*, i8** %[[START_FILE_ARG_0_PTR]]
+; GCDA-NEXT: %[[START_FILE_ARG_1_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[START_FILE_ARGS]], i32 0, i32 1
+; GCDA-NEXT: %[[START_FILE_ARG_1:.*]] = load i8*, i8** %[[START_FILE_ARG_1_PTR]]
+; GCDA-NEXT: %[[START_FILE_ARG_2_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[START_FILE_ARGS]], i32 0, i32 2
+; GCDA-NEXT: %[[START_FILE_ARG_2:.*]] = load i32, i32* %[[START_FILE_ARG_2_PTR]]
+; GCDA-NEXT: call void @llvm_gcda_start_file(i8* %[[START_FILE_ARG_0]], i8* %[[START_FILE_ARG_1]], i32 %[[START_FILE_ARG_2]])
+; GCDA-NEXT: %[[NUM_COUNTERS_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[FILE_INFO]], i32 0, i32 1
+; GCDA-NEXT: %[[NUM_COUNTERS:.*]] = load i32, i32* %[[NUM_COUNTERS_PTR]]
+; GCDA-NEXT: %[[EMIT_FUN_ARGS_ARRAY_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[FILE_INFO]], i32 0, i32 2
+; GCDA-NEXT: %[[EMIT_FUN_ARGS_ARRAY:.*]] = load {{.*}}*, {{.*}}** %[[EMIT_FUN_ARGS_ARRAY_PTR]]
+; GCDA-NEXT: %[[EMIT_ARCS_ARGS_ARRAY_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[FILE_INFO]], i32 0, i32 3
+; GCDA-NEXT: %[[EMIT_ARCS_ARGS_ARRAY:.*]] = load {{.*}}*, {{.*}}** %[[EMIT_ARCS_ARGS_ARRAY_PTR]]
+; GCDA-NEXT: %[[ENTER_COUNTER_LOOP_COND:.*]] = icmp slt i32 0, %[[NUM_COUNTERS]]
+; GCDA-NEXT: br i1 %[[ENTER_COUNTER_LOOP_COND]], label %[[COUNTER_LOOP:.*]], label %[[FILE_LOOP_LATCH]]
+;
+; GCDA: [[COUNTER_LOOP]]:
+; GCDA-NEXT: %[[JV:.*]] = phi i32 [ 0, %[[FILE_LOOP_HEADER]] ], [ %[[NEXT_JV:.*]], %[[COUNTER_LOOP]] ]
+; GCDA-NEXT: %[[EMIT_FUN_ARGS:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_FUN_ARGS_ARRAY]], i32 %[[JV]]
+; GCDA-NEXT: %[[EMIT_FUN_ARG_0_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_FUN_ARGS]], i32 0, i32 0
+; GCDA-NEXT: %[[EMIT_FUN_ARG_0:.*]] = load i32, i32* %[[EMIT_FUN_ARG_0_PTR]]
+; GCDA-NEXT: %[[EMIT_FUN_ARG_1_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_FUN_ARGS]], i32 0, i32 1
+; GCDA-NEXT: %[[EMIT_FUN_ARG_1:.*]] = load i8*, i8** %[[EMIT_FUN_ARG_1_PTR]]
+; GCDA-NEXT: %[[EMIT_FUN_ARG_2_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_FUN_ARGS]], i32 0, i32 2
+; GCDA-NEXT: %[[EMIT_FUN_ARG_2:.*]] = load i32, i32* %[[EMIT_FUN_ARG_2_PTR]]
+; GCDA-NEXT: %[[EMIT_FUN_ARG_3_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_FUN_ARGS]], i32 0, i32 3
+; GCDA-NEXT: %[[EMIT_FUN_ARG_3:.*]] = load i8, i8* %[[EMIT_FUN_ARG_3_PTR]]
+; GCDA-NEXT: %[[EMIT_FUN_ARG_4_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_FUN_ARGS]], i32 0, i32 4
+; GCDA-NEXT: %[[EMIT_FUN_ARG_4:.*]] = load i32, i32* %[[EMIT_FUN_ARG_4_PTR]]
+; GCDA-NEXT: call void @llvm_gcda_emit_function(i32 %[[EMIT_FUN_ARG_0]],
+; GCDA-SAME: i8* %[[EMIT_FUN_ARG_1]],
+; GCDA-SAME: i32 %[[EMIT_FUN_ARG_2]],
+; GCDA-SAME: i8 %[[EMIT_FUN_ARG_3]],
+; GCDA-SAME: i32 %[[EMIT_FUN_ARG_4]])
+; GCDA-NEXT: %[[EMIT_ARCS_ARGS:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_ARCS_ARGS_ARRAY]], i32 %[[JV]]
+; GCDA-NEXT: %[[EMIT_ARCS_ARG_0_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_ARCS_ARGS]], i32 0, i32 0
+; GCDA-NEXT: %[[EMIT_ARCS_ARG_0:.*]] = load i32, i32* %[[EMIT_ARCS_ARG_0_PTR]]
+; GCDA-NEXT: %[[EMIT_ARCS_ARG_1_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[EMIT_ARCS_ARGS]], i32 0, i32 1
+; GCDA-NEXT: %[[EMIT_ARCS_ARG_1:.*]] = load i64*, i64** %[[EMIT_ARCS_ARG_1_PTR]]
+; GCDA-NEXT: call void @llvm_gcda_emit_arcs(i32 %[[EMIT_ARCS_ARG_0]],
+; GCDA-SAME: i64* %[[EMIT_ARCS_ARG_1]])
+; GCDA-NEXT: %[[NEXT_JV]] = add i32 %[[JV]], 1
+; GCDA-NEXT: %[[COUNTER_LOOP_COND:.*]] = icmp slt i32 %[[NEXT_JV]], %[[NUM_COUNTERS]]
+; GCDA-NEXT: br i1 %[[COUNTER_LOOP_COND]], label %[[COUNTER_LOOP]], label %[[FILE_LOOP_LATCH]]
+;
+; GCDA: [[FILE_LOOP_LATCH]]:
+; GCDA-NEXT: call void @llvm_gcda_summary_info()
+; GCDA-NEXT: call void @llvm_gcda_end_file()
+; GCDA-NEXT: %[[NEXT_IV]] = add i32 %[[IV]], 1
+; GCDA-NEXT: %[[FILE_LOOP_COND:.*]] = icmp slt i32 %[[NEXT_IV]], 1
+; GCDA-NEXT: br i1 %[[FILE_LOOP_COND]], label %[[FILE_LOOP_HEADER]], label %[[EXIT:.*]]
+;
+; GCDA: [[EXIT]]:
+; GCDA-NEXT: ret void
; GCNO: == foo (0) @
; GCNO-NOT: == bar ({{[0-9]+}}) @
OpenPOWER on IntegriCloud