Skip to content

[SYCL][sycl-post-link] Implement transformation of sycl-properties annotations #5940

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
; RUN: sycl-post-link --device-globals --ir-output-only -S %s -o %t.ll
; RUN: FileCheck %s -input-file=%t.ll
;
; TODO: Remove --device-globals once other features start using compile-time
; properties.
;
; Tests the translation of "sycl-properties" pointer annotations to pointer
; annotations the SPIR-V translator will produce decorations from.
; NOTE: These use SYCL property meta-names that are currently only intended for
; use in attributes-to-metadata translations, but sycl-post-link does not
; currently make the distinction so we will use them for the purpose of
; testing the transformations.

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
target triple = "spir64-unknown-unknown"

%struct.foo = type { i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)* }

$_ZTSZ4mainEUlvE_ = comdat any

@.str = private unnamed_addr constant [16 x i8] c"sycl-properties\00", section "llvm.metadata"
@.str.1 = private unnamed_addr constant [36 x i8] c"sycl-properties-ptr-annotations.cpp\00", section "llvm.metadata"
@.str.2 = private unnamed_addr constant [15 x i8] c"sycl-init-mode\00", section "llvm.metadata"
@.str.3 = private unnamed_addr constant [2 x i8] c"1\00", section "llvm.metadata"
@.str.4 = private unnamed_addr constant [22 x i8] c"sycl-implement-in-csr\00", section "llvm.metadata"
@.str.5 = private unnamed_addr constant [5 x i8] c"true\00", section "llvm.metadata"
@.args = private unnamed_addr constant { [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* } { [15 x i8]* @.str.2, [2 x i8]*@.str.3, [22 x i8]* @.str.4, [5 x i8]* @.str.5 }, section "llvm.metadata"
@.args.6 = private unnamed_addr constant { [15 x i8]*, [2 x i8]* } { [15 x i8]* @.str.2, [2 x i8]* @.str.3 }, section "llvm.metadata"
@.args.7 = private unnamed_addr constant { [22 x i8]*, [5 x i8]* } { [22 x i8]* @.str.4, [5 x i8]* @.str.5 }, section "llvm.metadata"
@.args.8 = private unnamed_addr constant { [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* } { [15 x i8]* @.str.2, [2 x i8]* @.str.3, [22 x i8]* @.str.4, [5 x i8]* @.str.5 }, section "llvm.metadata"
@.str.9 = private unnamed_addr constant [18 x i8] c"sycl-unrecognized\00", section "llvm.metadata"
@.args.10 = private unnamed_addr constant { [15 x i8]*, [2 x i8]*, [18 x i8]*, i8* } { [15 x i8]* @.str.2, [2 x i8]* @.str.3, [18 x i8]* @.str.9, i8* null }, section "llvm.metadata"
@.args.11 = private unnamed_addr constant { [18 x i8]*, i8* } { [18 x i8]* @.str.9, i8* null }, section "llvm.metadata"

;CHECK: @[[NewAnnotStr1:.*]] = private unnamed_addr constant [24 x i8] c"{6148:\221\22}{6149:\22true\22}\00", section "llvm.metadata"
;CHECK: @[[NewAnnotStr2:.*]] = private unnamed_addr constant [11 x i8] c"{6148:\221\22}\00", section "llvm.metadata"
;CHECK: @[[NewAnnotStr3:.*]] = private unnamed_addr constant [14 x i8] c"{6149:\22true\22}\00", section "llvm.metadata"

; Function Attrs: mustprogress norecurse
define weak_odr dso_local spir_kernel void @_ZTSZ4mainEUlvE_() local_unnamed_addr #0 comdat !kernel_arg_buffer_location !7 !sycl_kernel_omit_args !7 {
entry:
%x.i = alloca %struct.foo, align 8
%x.ascast.i = addrspacecast %struct.foo* %x.i to %struct.foo addrspace(4)*
%0 = bitcast %struct.foo* %x.i to i8*
%1 = addrspacecast i8* %0 to i8 addrspace(4)*
%2 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %1, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 5, i8* bitcast ({ [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* }* @.args to i8*)) #2
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %1, i8* getelementptr inbounds ([24 x i8], [24 x i8]* @[[NewAnnotStr1]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 5, i8* null)
%b.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 1
%3 = bitcast i32 addrspace(4)* addrspace(4)* %b.i to i8 addrspace(4)*
%4 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %3, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 6, i8* bitcast ({ [15 x i8]*, [2 x i8]* }* @.args.6 to i8*)) #2
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %3, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @[[NewAnnotStr2]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 6, i8* null)
%c.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 2
%5 = bitcast i32 addrspace(4)* addrspace(4)* %c.i to i8 addrspace(4)*
%6 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %5, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 7, i8* bitcast ({ [22 x i8]*, [5 x i8]* }* @.args.7 to i8*)) #2
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %5, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @[[NewAnnotStr3]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 7, i8* null)
%d.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 3
%7 = bitcast i32 addrspace(4)* addrspace(4)* %d.i to i8 addrspace(4)*
%8 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %7, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 8, i8* bitcast ({ [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* }* @.args.8 to i8*)) #2
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %7, i8* getelementptr inbounds ([24 x i8], [24 x i8]* @[[NewAnnotStr1]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 8, i8* null)
%e.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 4
%9 = bitcast i32 addrspace(4)* addrspace(4)* %e.i to i8 addrspace(4)*
%10 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %9, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 9, i8* bitcast ({ [15 x i8]*, [2 x i8]*, [18 x i8]*, i8* }* @.args.10 to i8*)) #2
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %9, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @[[NewAnnotStr2]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 9, i8* null)
%f.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 5
%11 = bitcast i32 addrspace(4)* addrspace(4)* %f.i to i8 addrspace(4)*
%12 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %11, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 10, i8* bitcast ({ [18 x i8]*, i8* }* @.args.11 to i8*)) #2
; CHECK-NOT: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.
%g.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 6
%13 = bitcast i32 addrspace(4)* addrspace(4)* %g.i to i8 addrspace(4)*
%14 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %13, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 11, i8* null) #2
ret void
}

; Function Attrs: inaccessiblememonly nofree nosync nounwind willreturn
declare i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)*, i8*, i8*, i32, i8*) #1

attributes #0 = { mustprogress norecurse "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="sycl-properties-ptr-annotations.cpp" "uniform-work-group-size"="true" }
attributes #1 = { inaccessiblememonly nofree nosync nounwind willreturn }
attributes #2 = { nounwind }

!opencl.spir.version = !{!0, !0, !0, !0, !0, !0}
!spirv.Source = !{!1, !1, !1, !1, !1, !1}
!llvm.ident = !{!2, !3, !3, !3, !4, !3}
!llvm.module.flags = !{!5, !6}

!0 = !{i32 1, i32 2}
!1 = !{i32 4, i32 100000}
!2 = !{!"clang version 15.0.0"}
!3 = !{!"clang version 15.0.0"}
!4 = !{!"clang version 15.0.0"}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 7, !"frame-pointer", i32 2}
!7 = !{}
131 changes: 131 additions & 0 deletions llvm/tools/sycl-post-link/CompileTimePropertiesPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"

using namespace llvm;

Expand Down Expand Up @@ -90,6 +93,15 @@ MDNode *buildSpirvDecorMetadata(LLVMContext &Ctx, uint32_t OpCode,
return MDNode::get(Ctx, MD);
}

Optional<StringRef> getGlobalVariableString(const Value *StringV) {
if (const auto *StringGV = dyn_cast<GlobalVariable>(StringV))
if (const auto *StringData =
dyn_cast<ConstantDataSequential>(StringGV->getInitializer()))
if (StringData->isCString())
return StringData->getAsCString();
return {};
}

} // anonymous namespace

PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
Expand Down Expand Up @@ -142,9 +154,128 @@ PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
}
}

// Check pointer annotations.
SmallVector<IntrinsicInst *, 4> RemovableAnnots;
for (Function &F : M)
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I)
if (auto *IntrInst = dyn_cast<IntrinsicInst>(&*I))
if (IntrInst->getIntrinsicID() == Intrinsic::ptr_annotation &&
transformSYCLPropertiesAnnotation(M, IntrInst, RemovableAnnots))
CompileTimePropertiesMet = true;

// Remove irrelevant "sycl-properties" annotations after the transformations.
for (IntrinsicInst *IntrInst : RemovableAnnots) {
assert(IntrInst->getNumUses() == 0);
IntrInst->eraseFromParent();
}

// The pass just adds some metadata to the module, it should not ruin
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this comment is actual now because the pass doesn't just add some metadata anymore. Can rewriting the @llvm.ptr.annotation intrinsics have any influence on the analysis?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't imagine changing the annotation strings of a llvm.ptr.annotation with our own "sycl-properties" special-name should affect any analyses. However, I don't know if removing an annotation could affect any previous analyses. @AlexeySachkov - Do you know?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kbobrovs - Do you have some insight into this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we really care if this change can affect transformation (and therefore lead to different IR). Theoretically it could affect subsequent IR t-forms happening before SPIRV generation if they depend on llvm.ptr.annotations (maybe transitively via Analyses). But AFAICS, this is the last tform before SPIRV.

BTW, If this transformation does not require fully linked program, then sycl-post-link would be a wrong place for it. It is always preferable to put additional IR passes to compilation (via BakendUtil.cpp) over putting them into post-link.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, If this transformation does not require fully linked program, then sycl-post-link would be a wrong place for it. It is always preferable to put additional IR passes to compilation (via BakendUtil.cpp) over putting them into post-link.

At the moment I don't believe it needs a fully linked program, but we could have a similar situation in the future to the devce_global where one of the properties need metadata information propagated to the runtime. We could of course create a new representation sycl-post-link would need to look for, but it does complicate the design.

Likewise, we would be splitting the property-translation logic, that is some would be done in additional IR pass (annotations -> annotations) while others would be done in sycl-post-link (IR attributes -> metadata). Would there be a good way for the two to share some logic?

@gmlueck - Ping in case you have some opinions on this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is the pass that converts @llvm.ptr.annotation from the form that contains the property names (strings) into the form that contains SPIR-V decoration numbers? (This follows the design in #5884.) Correct?

That pass is part of the general logic for converting LLVM IR into a "SPIR-V friendly form", and I thought we did all of this logic in sycl-post-link, just before we translate to SPIR-V. One advantage of this, I suppose, is that we can avoid doing this translation for targets that don't use SPIR-V.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed the implementation of that pass, currently shared with the logic for translating IR attributes.

Since @kbobrovs suggests for the pass to be part of BackendUtil.cpp, I believe we should be able to make it an elective pass that is only run when SPIR-V is the target, while other backend targets can use their own pass for the translations. However, for device_global sycl-post-link still needs to create the unique ID and communicate it to the runtime. We may be able to split the generation of the unique ID and the generation of the corresponding metadata to an earlier IR pass, but in that case sycl-post-link would have to parse the "SPIR-V friendly" metadata and base the information for the runtime on that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may be able to split the generation of the unique ID and the generation of the corresponding metadata to an earlier IR pass, but in that case sycl-post-link would have to parse the "SPIR-V friendly" metadata and base the information for the runtime on that.

Isn't this a reason not to move the translation to "SPIR-V friendly" form to BackendUtil.cpp? If we did this, then sycl-post-link needs to understand either the SPIR-V friendly form or the normal LLVM IR form (depending on whether the target supports SPIR-V)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we did this, then sycl-post-link needs to understand either the SPIR-V friendly form or the normal LLVM IR form (depending on whether the target supports SPIR-V)?

Either that, or we would make a common part of the pass (or another pass) that adds some new information that sycl-post-link will consume. It does complicate the design, but it would make backend-specific parsing of properties easier.

Either way, I think it should be considered for the entire pass rather than the changes made in this. @kbobrovs do you think there would be a problem in going with it as part of sycl-post-link for now and then discuss the transition to BackendUtil.cpp separately?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@steffenlarsen, I think transition to BackendUtil.cpp should be discussed separately, my comment was not meant to hold this PR.

A note about BackendUtil.cpp vs sycl-post-link.cpp. The original intent of sycl-post-link was to perform transformations which can not be done w/o knowing the entire program - such as assigning specialization constant IDs. The more transformations are implemented in sycl-post-link, the farther SYCL is from other compilers many of which don't even use any additional link-time IR transformations by default. It is like having a "hidden pass manager" in the form of the sycl-post-link, which bypasses clang optimization/transformation control mechanisms. There are some other disadvantages: extra link time (important for device libraries, which get compiled once and linked many times), compiler developers need to run post-link to see final code before SPIRV.

// any analysis, but we need return PreservedAnalyses::none() to inform
// the caller that at least one compile-time property was met.
return CompileTimePropertiesMet ? PreservedAnalyses::none()
: PreservedAnalyses::all();
}

// Returns true if the transformation changed IntrInst.
bool CompileTimePropertiesPass::transformSYCLPropertiesAnnotation(
Module &M, IntrinsicInst *IntrInst,
SmallVectorImpl<IntrinsicInst *> &RemovableAnnotations) {
assert(IntrInst->getIntrinsicID() == Intrinsic::ptr_annotation &&
"Intrinsic is not a pointer annotation.");
assert(IntrInst->arg_size() == 5 &&
"Unexpected number of arguments in annotation intrinsic.");

// Get the global variable with the annotation string.
const GlobalVariable *AnnotStrArgGV = nullptr;
const Value *IntrAnnotStringArg = IntrInst->getArgOperand(1);
if (auto *GEP = dyn_cast<GEPOperator>(IntrAnnotStringArg))
if (auto *C = dyn_cast<Constant>(GEP->getOperand(0)))
AnnotStrArgGV = dyn_cast<GlobalVariable>(C);
if (!AnnotStrArgGV)
return false;

// We only need to consider annotations with "sycl-properties" annotation
// string.
Optional<StringRef> AnnotStr = getGlobalVariableString(AnnotStrArgGV);
if (!AnnotStr || AnnotStr->str() != "sycl-properties")
return false;

// Read the annotation values and create the new annotation string.
std::string NewAnnotString = "";
if (const auto *Cast =
dyn_cast<BitCastOperator>(IntrInst->getArgOperand(4))) {
if (const auto *AnnotValsGV =
dyn_cast<GlobalVariable>(Cast->getOperand(0))) {
if (const auto *AnnotValsAggr =
dyn_cast<ConstantAggregate>(AnnotValsGV->getInitializer())) {
assert(
(AnnotValsAggr->getNumOperands() & 1) == 0 &&
"sycl-properties annotation must have an even number of annotation "
"values.");

// Iterate over the pairs of property meta-names and meta-values.
for (size_t I = 0; I < AnnotValsAggr->getNumOperands(); I += 2) {
Optional<StringRef> PropMetaName =
getGlobalVariableString(AnnotValsAggr->getOperand(I));
Optional<StringRef> PropMetaValue =
getGlobalVariableString(AnnotValsAggr->getOperand(I + 1));

assert(PropMetaName &&
"Unexpected format for property name in annotation.");

auto DecorIt = SpirvDecorMap.find(*PropMetaName);
if (DecorIt == SpirvDecorMap.end())
continue;
uint32_t DecorCode = DecorIt->second.Code;

// Expected format is '{X}' or '{X:Y}' where X is decoration ID and
// Y is the value if present. It encloses Y in " to ensure that
// string values are handled correctly. Note that " around values are
// always valid, even if the decoration parameters are not strings.
NewAnnotString += "{" + std::to_string(DecorCode);
if (PropMetaValue)
NewAnnotString += ":\"" + PropMetaValue->str() + "\"";
NewAnnotString += "}";
}
}
}
}

// If the new annotation string is empty there is no reason to keep it, so
// replace it with the first operand and mark it for removal.
if (NewAnnotString.empty()) {
IntrInst->replaceAllUsesWith(IntrInst->getOperand(0));
RemovableAnnotations.push_back(IntrInst);
return true;
}

// Either reuse a previously generated one or create a new global variable
// with the new annotation string.
GlobalVariable *NewAnnotStringGV = nullptr;
auto ExistingNewAnnotStringIt = ReusableAnnotStrings.find(NewAnnotString);
if (ExistingNewAnnotStringIt != ReusableAnnotStrings.end()) {
NewAnnotStringGV = ExistingNewAnnotStringIt->second;
} else {
Constant *NewAnnotStringData =
ConstantDataArray::getString(M.getContext(), NewAnnotString);
NewAnnotStringGV = new GlobalVariable(M, NewAnnotStringData->getType(),
true, GlobalValue::PrivateLinkage,
NewAnnotStringData, ".str");
NewAnnotStringGV->setSection(AnnotStrArgGV->getSection());
NewAnnotStringGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
ReusableAnnotStrings.insert({NewAnnotString, NewAnnotStringGV});
}

// Replace the annotation string with a bitcast of the new global variable.
IntrInst->setArgOperand(
1, ConstantExpr::getBitCast(NewAnnotStringGV,
IntrAnnotStringArg->getType()));

// The values are not in the annotation string, so we can remove the original
// annotation value.
unsigned DefaultAS = M.getDataLayout().getDefaultGlobalsAddressSpace();
Type *Int8Ty = IntegerType::getInt8Ty(M.getContext());
PointerType *Int8DefaultASPtrTy = Int8Ty->getPointerTo(DefaultAS);
IntrInst->setArgOperand(4, ConstantPointerNull::get(Int8DefaultASPtrTy));
return true;
}
18 changes: 18 additions & 0 deletions llvm/tools/sycl-post-link/CompileTimePropertiesPass.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,33 @@
#include "llvm/IR/PassManager.h"

#include <cassert>
#include <string>
#include <unordered_map>

namespace llvm {

// Forward declaration.
class IntrinsicInst;

class CompileTimePropertiesPass
: public PassInfoMixin<CompileTimePropertiesPass> {
public:
// Enriches the module with metadata that describes the found variables for
// the SPIRV-LLVM Translator.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);

private:
// Transforms llvm.ptr.annotations with the "sycl-properties" annotation
// string into another llvm.ptr.annotations call in a format consumable by
// the SPIR-V translator.
bool transformSYCLPropertiesAnnotation(
Module &M, IntrinsicInst *IntrInst,
SmallVectorImpl<IntrinsicInst *> &RemovableAnnotations);

// Map for keeping track of global variables generated for annotation strings.
// This allows reuse for annotations with the same generated annotation
// strings.
std::unordered_map<std::string, GlobalVariable *> ReusableAnnotStrings;
};

namespace detail {
Expand Down