Skip to content

Commit 201f902

Browse files
authored
[SYCL] Generate an opt report of kernel arguments. (#3492)
This implementation will be followed by an upcoming PR that will have the purpose of creating a more user-friendly report. Signed-off-by: Zahira Ammarguellat <[email protected]>
1 parent cef2dd6 commit 201f902

File tree

7 files changed

+238
-21
lines changed

7 files changed

+238
-21
lines changed

clang/include/clang/Basic/Diagnostic.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/Basic/DiagnosticOptions.h"
1919
#include "clang/Basic/SourceLocation.h"
2020
#include "clang/Basic/Specifiers.h"
21+
#include "clang/Basic/SyclOptReportHandler.h"
2122
#include "llvm/ADT/ArrayRef.h"
2223
#include "llvm/ADT/DenseMap.h"
2324
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -294,6 +295,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
294295
DiagnosticConsumer *Client = nullptr;
295296
std::unique_ptr<DiagnosticConsumer> Owner;
296297
SourceManager *SourceMgr = nullptr;
298+
SyclOptReportHandler OptReportHandler;
297299

298300
/// Mapping information for diagnostics.
299301
///
@@ -547,6 +549,12 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
547549
LLVM_DUMP_METHOD void dump() const;
548550
LLVM_DUMP_METHOD void dump(StringRef DiagName) const;
549551

552+
/// Retrieve the report SyclOptReport info.
553+
SyclOptReportHandler &getSYCLOptReportHandler() { return OptReportHandler; }
554+
const SyclOptReportHandler &getSYCLOptReportHandler() const {
555+
return OptReportHandler;
556+
}
557+
550558
const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
551559
return Diags;
552560
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===---------------------- SyclOptReportHandler.h --------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file
10+
/// Defines clang::SyclOptReportHandler class.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_BASIC_SYCLOPTREPORTHANDLER_H
15+
#define LLVM_CLANG_BASIC_SYCLOPTREPORTHANDLER_H
16+
17+
#include "clang/Basic/SourceLocation.h"
18+
#include "llvm/ADT/DenseMap.h"
19+
#include "llvm/ADT/StringRef.h"
20+
21+
namespace clang {
22+
23+
class FunctionDecl;
24+
25+
class SyclOptReportHandler {
26+
private:
27+
struct OptReportInfo {
28+
std::string KernelArgName;
29+
std::string KernelArgType;
30+
SourceLocation KernelArgLoc;
31+
32+
OptReportInfo(std::string ArgName, std::string ArgType,
33+
SourceLocation ArgLoc)
34+
: KernelArgName(std::move(ArgName)), KernelArgType(std::move(ArgType)),
35+
KernelArgLoc(ArgLoc) {}
36+
};
37+
llvm::DenseMap<const FunctionDecl *, SmallVector<OptReportInfo>> Map;
38+
39+
public:
40+
void AddKernelArgs(const FunctionDecl *FD, std::string ArgName,
41+
std::string ArgType, SourceLocation ArgLoc) {
42+
Map[FD].emplace_back(ArgName, ArgType, ArgLoc);
43+
}
44+
SmallVector<OptReportInfo> &GetInfo(const FunctionDecl *FD) {
45+
auto It = Map.find(FD);
46+
assert(It != Map.end());
47+
return It->second;
48+
}
49+
50+
bool HasOptReportInfo(const FunctionDecl *FD) const {
51+
return Map.find(FD) != Map.end();
52+
}
53+
};
54+
55+
} // namespace clang
56+
57+
#endif // LLVM_CLANG_BASIC_SYCLOPTREPORTHANDLER_H

clang/lib/CodeGen/CGSYCLRuntime.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include "CodeGenFunction.h"
1515
#include "clang/AST/Attr.h"
1616
#include "clang/AST/Decl.h"
17+
#include "clang/Basic/SourceLocation.h"
18+
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
1719
#include "llvm/IR/Instructions.h"
1820
#include <assert.h>
1921

clang/lib/CodeGen/CodeGenAction.cpp

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -304,28 +304,12 @@ namespace clang {
304304
return;
305305

306306
LLVMContext &Ctx = getModule()->getContext();
307+
307308
std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler =
308309
Ctx.getDiagnosticHandler();
309310
Ctx.setDiagnosticHandler(std::make_unique<ClangDiagnosticHandler>(
310311
CodeGenOpts, this));
311-
312-
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
313-
setupLLVMOptimizationRemarks(
314-
Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
315-
CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
316-
CodeGenOpts.DiagnosticsHotnessThreshold);
317-
318-
if (Error E = OptRecordFileOrErr.takeError()) {
319-
reportOptRecordError(std::move(E), Diags, CodeGenOpts);
320-
return;
321-
}
322-
323-
std::unique_ptr<llvm::ToolOutputFile> OptRecordFile =
324-
std::move(*OptRecordFileOrErr);
325-
326-
if (OptRecordFile &&
327-
CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone)
328-
Ctx.setDiagnosticsHotnessRequested(true);
312+
// The diagnostic handler is now processed in OptRecordFileRAII.
329313

330314
// The parallel_for_work_group legalization pass can emit calls to
331315
// builtins function. Definitions of those builtins can be provided in
@@ -349,9 +333,6 @@ namespace clang {
349333
getModule(), Action, std::move(AsmOutStream));
350334

351335
Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler));
352-
353-
if (OptRecordFile)
354-
OptRecordFile->keep();
355336
}
356337

357338
void HandleTagDeclDefinition(TagDecl *D) override {
@@ -1046,8 +1027,51 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
10461027
return {};
10471028
}
10481029

1030+
namespace {
1031+
// Handles the initialization and cleanup of the OptRecordFile. This
1032+
// customization allows initialization before the clang codegen runs
1033+
// so it can also emit to the opt report.
1034+
struct OptRecordFileRAII {
1035+
std::unique_ptr<llvm::ToolOutputFile> OptRecordFile;
1036+
std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler;
1037+
llvm::LLVMContext &Ctx;
1038+
1039+
OptRecordFileRAII(CodeGenAction &CGA, llvm::LLVMContext &Ctx,
1040+
BackendConsumer &BC)
1041+
: Ctx(Ctx), OldDiagnosticHandler(Ctx.getDiagnosticHandler()) {
1042+
1043+
CompilerInstance &CI = CGA.getCompilerInstance();
1044+
CodeGenOptions &CodeGenOpts = CI.getCodeGenOpts();
1045+
1046+
Ctx.setDiagnosticHandler(
1047+
std::make_unique<ClangDiagnosticHandler>(CodeGenOpts, &BC));
1048+
1049+
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
1050+
setupLLVMOptimizationRemarks(
1051+
Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
1052+
CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness,
1053+
CodeGenOpts.DiagnosticsHotnessThreshold);
1054+
1055+
if (Error E = OptRecordFileOrErr.takeError())
1056+
reportOptRecordError(std::move(E), CI.getDiagnostics(), CodeGenOpts);
1057+
else
1058+
OptRecordFile = std::move(*OptRecordFileOrErr);
1059+
1060+
if (OptRecordFile &&
1061+
CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone)
1062+
Ctx.setDiagnosticsHotnessRequested(true);
1063+
}
1064+
~OptRecordFileRAII() {
1065+
Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler));
1066+
if (OptRecordFile)
1067+
OptRecordFile->keep();
1068+
}
1069+
};
1070+
} // namespace
1071+
10491072
void CodeGenAction::ExecuteAction() {
10501073
if (getCurrentFileKind().getLanguage() != Language::LLVM_IR) {
1074+
OptRecordFileRAII ORF(*this, *VMContext, *BEConsumer);
10511075
this->ASTFrontendAction::ExecuteAction();
10521076
return;
10531077
}

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "clang/CodeGen/CGFunctionInfo.h"
3636
#include "clang/Frontend/FrontendDiagnostic.h"
3737
#include "llvm/ADT/ArrayRef.h"
38+
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
3839
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
3940
#include "llvm/IR/DataLayout.h"
4041
#include "llvm/IR/Dominators.h"
@@ -1521,6 +1522,25 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
15211522
// Emit the standard function prologue.
15221523
StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
15231524

1525+
SyclOptReportHandler &OptReportHandler =
1526+
CGM.getDiags().getSYCLOptReportHandler();
1527+
if (OptReportHandler.HasOptReportInfo(FD)) {
1528+
llvm::OptimizationRemarkEmitter ORE(Fn);
1529+
for (auto ORI : llvm::enumerate(OptReportHandler.GetInfo(FD))) {
1530+
llvm::DiagnosticLocation DL =
1531+
SourceLocToDebugLoc(ORI.value().KernelArgLoc);
1532+
std::string KAN = ORI.value().KernelArgName;
1533+
llvm::OptimizationRemark Remark("sycl", "Region", DL,
1534+
&Fn->getEntryBlock());
1535+
Remark << "Argument " << llvm::ore::NV("Argument", ORI.index())
1536+
<< " for function kernel: "
1537+
<< llvm::ore::NV(KAN.empty() ? "&" : "") << " " << Fn->getName()
1538+
<< "." << llvm::ore::NV(KAN.empty() ? " " : KAN) << "("
1539+
<< ORI.value().KernelArgType << ")";
1540+
ORE.emit(Remark);
1541+
}
1542+
}
1543+
15241544
// Save parameters for coroutine function.
15251545
if (Body && isa_and_nonnull<CoroutineBodyStmt>(Body))
15261546
for (const auto *ParamDecl : FD->parameters())

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
17681768

17691769
void addParam(const FieldDecl *FD, QualType FieldTy) {
17701770
ParamDesc newParamDesc = makeParamDesc(FD, FieldTy);
1771+
SemaRef.getDiagnostics().getSYCLOptReportHandler().AddKernelArgs(
1772+
KernelDecl, FD->getName().data(), FieldTy.getAsString(),
1773+
FD->getLocation());
17711774
addParam(newParamDesc, FieldTy);
17721775
}
17731776

@@ -1778,6 +1781,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
17781781
StringRef Name = "_arg__base";
17791782
ParamDesc newParamDesc =
17801783
makeParamDesc(SemaRef.getASTContext(), Name, FieldTy);
1784+
SemaRef.getDiagnostics().getSYCLOptReportHandler().AddKernelArgs(
1785+
KernelDecl, "", FieldTy.getAsString(), BS.getBaseTypeLoc());
17811786
addParam(newParamDesc, FieldTy);
17821787
}
17831788
// Add a parameter with specified name and type
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl-is-device \
2+
// RUN: -Wno-sycl-2017-compat -emit-llvm-bc %s -o %t-host.bc -opt-record-file %t-host.yaml
3+
// RUN: FileCheck -check-prefix=CHECK --input-file %t-host.yaml %s
4+
// The test generates remarks about the kernel argument, their location and type
5+
// in the resulting yaml file.
6+
7+
#include "Inputs/sycl.hpp"
8+
9+
class second_base {
10+
public:
11+
int *e;
12+
};
13+
14+
class InnerFieldBase {
15+
public:
16+
int d;
17+
};
18+
class InnerField : public InnerFieldBase {
19+
int c;
20+
};
21+
22+
struct base {
23+
public:
24+
int b;
25+
InnerField obj;
26+
};
27+
28+
//CHECK: --- !Passed
29+
//CHECK: Pass:{{.*}}sycl
30+
//CHECK: Name:{{.*}}Region
31+
//CHECK: DebugLoc:{{.*}} { File: '{{.*}}kernel-arg-opt-report.cpp',
32+
//CHECK: Line: 85, Column: 18 }
33+
//CHECK: Function: _ZTS7derived
34+
//CHECK: Args:
35+
//CHECK-NEXT: String: 'Argument '
36+
//CHECK-NEXT: Argument: '0'
37+
//CHECK-NEXT: String: ' for function kernel: '
38+
//CHECK-NEXT: String: '&'
39+
//CHECK-NEXT: String: ' '
40+
//CHECK-NEXT: String: _ZTS7derived
41+
//CHECK-NEXT: String: .
42+
//CHECK-NEXT: String: ' '
43+
//CHECK-NEXT: String: '('
44+
//CHECK-NEXT: String: struct base
45+
//CHECK-NEXT: String: ')'
46+
47+
//CHECK: --- !Passed
48+
//CHECK: Pass:{{.*}}sycl
49+
//CHECK: Name:{{.*}}Region
50+
//CHECK: DebugLoc:{{.*}} { File: '{{.*}}kernel-arg-opt-report.cpp',
51+
//CHECK: Line: 11, Column: 8 }
52+
//CHECK: Function: _ZTS7derived
53+
//CHECK: Args:
54+
//CHECK-NEXT: String: 'Argument '
55+
//CHECK-NEXT: Argument: '1'
56+
//CHECK-NEXT: String: ' for function kernel: '
57+
//CHECK-NEXT: String: ''
58+
//CHECK-NEXT: String: ' '
59+
//CHECK-NEXT: String: _ZTS7derived
60+
//CHECK-NEXT: String: .
61+
//CHECK-NEXT: String: e
62+
//CHECK-NEXT: String: '('
63+
//CHECK-NEXT: String: struct __wrapper_class
64+
//CHECK-NEXT: String: ')'
65+
66+
//CHECK: --- !Passed
67+
//CHECK: Pass:{{.*}}sycl
68+
//CHECK: Name:{{.*}}Region
69+
//CHECK: DebugLoc:{{.*}} { File: '{{.*}}kernel-arg-opt-report.cpp',
70+
//CHECK: Line: 86, Column: 7 }
71+
//CHECK: Function: _ZTS7derived
72+
//CHECK: Args:
73+
//CHECK-NEXT: String: 'Argument '
74+
//CHECK-NEXT: Argument: '2'
75+
//CHECK-NEXT: String: ' for function kernel: '
76+
//CHECK-NEXT: String: ''
77+
//CHECK-NEXT: String: ' '
78+
//CHECK-NEXT: String: _ZTS7derived
79+
//CHECK-NEXT: String: .
80+
//CHECK-NEXT: String: a
81+
//CHECK-NEXT: String: '('
82+
//CHECK-NEXT: String: int
83+
//CHECK-NEXT: String: ')'
84+
85+
struct derived : base, second_base {
86+
int a;
87+
88+
void operator()() const {
89+
}
90+
};
91+
92+
int main() {
93+
sycl::queue q;
94+
95+
q.submit([&](cl::sycl::handler &cgh) {
96+
derived f{};
97+
cgh.single_task(f);
98+
});
99+
100+
return 0;
101+
}

0 commit comments

Comments
 (0)