From 4084bb9da5b07d9a074e1cfec8279daa4d61ab56 Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Thu, 6 Mar 2014 06:10:02 +0000 Subject: [PATCH] PGO: add instrumentation for Objective-C methods. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203085 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjC.cpp | 5 +++ lib/CodeGen/CodeGenPGO.cpp | 27 ++++++++++++++-- .../CodeGenObjC/Inputs/instr-profile.profdata | 2 +- test/CodeGenObjC/instr-profile.m | 32 ++++++++++++++++--- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index c1d7d2024c..800d3a97dc 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -502,9 +502,14 @@ static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF, /// its pointer, name, and types registered in the class struture. void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { StartObjCMethod(OMD, OMD->getClassInterface(), OMD->getLocStart()); + PGO.assignRegionCounters(OMD, CurFn); assert(isa(OMD->getBody())); + RegionCounter Cnt = getPGORegionCounter(OMD->getBody()); + Cnt.beginRegion(Builder); EmitCompoundStmtWithoutScope(*cast(OMD->getBody())); FinishFunction(OMD->getBodyRBrace()); + PGO.emitWriteoutFunction(); + PGO.destroyRegionCounters(); } /// emitStructGetterCall - Call the runtime function to load a property diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp index 6678c37929..349160ad35 100644 --- a/lib/CodeGen/CodeGenPGO.cpp +++ b/lib/CodeGen/CodeGenPGO.cpp @@ -49,11 +49,17 @@ PGOProfileData::PGOProfileData(CodeGenModule &CGM, std::string Path) while (CurPtr < BufferEnd) { // Read the function name. const char *FuncStart = CurPtr; - CurPtr = strchr(CurPtr, ' '); + // For Objective-C methods, the name may include whitespace, so search + // backward from the end of the line to find the space that separates the + // name from the number of counters. (This is a temporary hack since we are + // going to completely replace this file format in the near future.) + CurPtr = strchr(CurPtr, '\n'); if (!CurPtr) { ReportBadPGOData(CGM, "pgo data file has malformed function entry"); return; } + while (*--CurPtr != ' ') + ; StringRef FuncName(FuncStart, CurPtr - FuncStart); // Read the number of counters. @@ -129,8 +135,10 @@ bool PGOProfileData::getFunctionCounts(StringRef FuncName, const char *CurPtr = DataBuffer->getBufferStart() + OffsetIter->getValue(); // Skip over the function name. - CurPtr = strchr(CurPtr, ' '); + CurPtr = strchr(CurPtr, '\n'); assert(CurPtr && "pgo-data has corrupted function entry"); + while (*--CurPtr != ' ') + ; // Read the number of counters. char *EndPtr; @@ -303,6 +311,10 @@ namespace { (*CounterMap)[S->getBody()] = NextCounter++; Visit(S->getBody()); } + void VisitObjCMethodDecl(const ObjCMethodDecl *S) { + (*CounterMap)[S->getBody()] = NextCounter++; + Visit(S->getBody()); + } /// Assign a counter to track the block following a label. void VisitLabelStmt(const LabelStmt *S) { (*CounterMap)[S] = NextCounter++; @@ -462,6 +474,13 @@ namespace { Visit(S->getBody()); } + void VisitObjCMethodDecl(const ObjCMethodDecl *S) { + RegionCounter Cnt(PGO, S->getBody()); + Cnt.beginRegion(); + (*CountMap)[S->getBody()] = PGO.getCurrentRegionCount(); + Visit(S->getBody()); + } + void VisitReturnStmt(const ReturnStmt *S) { RecordStmtCount(S); if (S->getRetValue()) @@ -781,6 +800,8 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) { MapRegionCounters Walker(RegionCounterMap); if (const FunctionDecl *FD = dyn_cast_or_null(D)) Walker.VisitFunctionDecl(FD); + else if (const ObjCMethodDecl *MD = dyn_cast_or_null(D)) + Walker.VisitObjCMethodDecl(MD); NumRegionCounters = Walker.NextCounter; } @@ -789,6 +810,8 @@ void CodeGenPGO::computeRegionCounts(const Decl *D) { ComputeRegionCounts Walker(StmtCountMap, *this); if (const FunctionDecl *FD = dyn_cast_or_null(D)) Walker.VisitFunctionDecl(FD); + else if (const ObjCMethodDecl *MD = dyn_cast_or_null(D)) + Walker.VisitObjCMethodDecl(MD); } void CodeGenPGO::emitCounterVariables() { diff --git a/test/CodeGenObjC/Inputs/instr-profile.profdata b/test/CodeGenObjC/Inputs/instr-profile.profdata index f3c03cc793..f068640dbc 100644 --- a/test/CodeGenObjC/Inputs/instr-profile.profdata +++ b/test/CodeGenObjC/Inputs/instr-profile.profdata @@ -1,4 +1,4 @@ -foreach 2 +instr-profile.m:+[A foreach:] 2 1 2 diff --git a/test/CodeGenObjC/instr-profile.m b/test/CodeGenObjC/instr-profile.m index e1b13edf21..f232d985d8 100644 --- a/test/CodeGenObjC/instr-profile.m +++ b/test/CodeGenObjC/instr-profile.m @@ -8,11 +8,24 @@ // RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%S/Inputs/instr-profile.profdata | FileCheck -check-prefix=PGOUSE %s #ifdef HAVE_FOUNDATION + // Use this to build an instrumented version to regenerate the input file. #import + #else + +// Minimal definitions to get this to compile without Foundation.h. + +@protocol NSObject +@end + +@interface NSObject +- (id)init; ++ (id)alloc; +@end + struct NSFastEnumerationState; -@interface NSArray +@interface NSArray : NSObject - (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state objects: (id*) buffer count: (unsigned long) bufferSize; @@ -22,17 +35,26 @@ struct NSFastEnumerationState; // PGOGEN: @[[FOR:__llvm_pgo_ctr[0-9]*]] = private global [2 x i64] zeroinitializer -// PGOGEN-LABEL: @foreach -// PGOUSE-LABEL: @foreach +@interface A : NSObject ++ (void)foreach: (NSArray *)array; +@end + +@implementation A +// PGOGEN-LABEL: define {{.*}}+[A foreach:] +// PGOUSE-LABEL: define {{.*}}+[A foreach:] // PGOGEN: store {{.*}} @[[FOR]], i64 0, i64 0 -void foreach(NSArray *array) { ++ (void)foreach: (NSArray *)array +{ // PGOGEN: store {{.*}} @[[FOR]], i64 0, i64 1 // FIXME: We don't emit branch weights for this yet. for (id x in array) { } } +@end int main(int argc, const char *argv[]) { + A *a = [[A alloc] init]; NSArray *array = [NSArray arrayWithObjects: @"0", @"1", (void*)0]; - foreach(array); + [A foreach: array]; + return 0; } -- 2.40.0