Skip to content

Commit 192e16d

Browse files
Recognize string as printf string, when any of uses is printf (#23337)
Currently constnt string literals used only by printf are recognized as printf strings and are stored in constant buffer. But when there is reference to that string, even unused it's no longer recognized as printf string and it's content is stored in .global buffer. This can lead to segfault in runtime, as when trying to use printf it will recieve GPU pointer. Co-authored-by: Skobejko, Milosz <[email protected]>
1 parent 065b904 commit 192e16d

File tree

4 files changed

+43
-18
lines changed

4 files changed

+43
-18
lines changed

IGC/Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/OpenCLPrintfAnalysis.cpp

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ void OpenCLPrintfAnalysis::addPrintfBufferArgs(Function &F) {
9595
ImplicitArgs::addImplicitArgs(F, implicitArgs, m_pMDUtils);
9696
}
9797

98-
bool isPrintfOnlyStringConstantImpl(const llvm::Value *v, std::set<const llvm::User *> &visited) {
98+
bool isPrintfStringConstantImpl(const llvm::Value *v, std::set<const llvm::User *> &visited) {
9999
// Recursively check the users of the value until reaching the top level
100100
// user or a call.
101101

@@ -114,7 +114,6 @@ bool isPrintfOnlyStringConstantImpl(const llvm::Value *v, std::set<const llvm::U
114114
continue;
115115
visited.insert(user);
116116

117-
bool res = false;
118117
if (const llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(user)) {
119118
// Stop when reaching a call and check if it is an opencl/oneapi
120119
// printf call.
@@ -124,30 +123,25 @@ bool isPrintfOnlyStringConstantImpl(const llvm::Value *v, std::set<const llvm::U
124123
OpenCLPrintfAnalysis::isBuiltinPrintf(target);
125124

126125
if (isStringLiteral) {
127-
res = true;
126+
return true;
128127
} else {
129128
unsigned int opIndex = call->getDataOperandNo(&use);
130-
res = isPrintfOnlyStringConstantImpl(target->arg_begin() + opIndex, visited);
129+
return isPrintfStringConstantImpl(target->arg_begin() + opIndex, visited);
131130
}
132131
} else if (llvm::dyn_cast<llvm::CastInst>(user) || llvm::dyn_cast<llvm::SelectInst>(user) ||
133132
llvm::dyn_cast<llvm::PHINode>(user)) {
134-
res = isPrintfOnlyStringConstantImpl(user, visited);
133+
return isPrintfStringConstantImpl(user, visited);
135134
} else if (const llvm::GetElementPtrInst *gep = llvm::dyn_cast<llvm::GetElementPtrInst>(user)) {
136135
if (gep->hasAllZeroIndices())
137-
res = isPrintfOnlyStringConstantImpl(user, visited);
136+
return isPrintfStringConstantImpl(user, visited);
138137
}
139-
140-
if (!res)
141-
return false;
142138
}
143-
144-
// Return true as every top level user is a printf call.
145-
return true;
139+
return false;
146140
}
147141

148-
// Check paths from a string literal to printf calls and return true if every
142+
// Check paths from a string literal to printf calls and return true if any
149143
// path lead to a printf call.
150-
bool OpenCLPrintfAnalysis::isPrintfOnlyStringConstant(const llvm::GlobalVariable *GV) {
144+
bool OpenCLPrintfAnalysis::isPrintfStringConstant(const llvm::GlobalVariable *GV) {
151145
const llvm::Constant *Initializer = GV->getInitializer();
152146
if (!Initializer) {
153147
return false;
@@ -166,7 +160,7 @@ bool OpenCLPrintfAnalysis::isPrintfOnlyStringConstant(const llvm::GlobalVariable
166160

167161
if (IsNullTerminatedString || IsZeroInitCharArray) {
168162
std::set<const llvm::User *> Visited;
169-
return isPrintfOnlyStringConstantImpl(GV, Visited);
163+
return isPrintfStringConstantImpl(GV, Visited);
170164
}
171165

172166
return false;

IGC/Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/OpenCLPrintfAnalysis.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class OpenCLPrintfAnalysis : public llvm::ModulePass, public llvm::InstVisitor<O
5252
// Return true if every top level user of a string literal is a printf
5353
// call. Note that the function is expected to work only before printf
5454
// expansion.
55-
static bool isPrintfOnlyStringConstant(const llvm::GlobalVariable *GV);
55+
static bool isPrintfStringConstant(const llvm::GlobalVariable *GV);
5656

5757
private:
5858
/// @brief Adds an implicit argument for address of printf output buffer

IGC/Compiler/Optimizer/OpenCLPasses/ProgramScopeConstants/ProgramScopeConstantAnalysis.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ bool ProgramScopeConstantAnalysis::runOnModule(Module &M) {
118118
InlineProgramScopeBufferType inlineProgramScopeBufferType = {};
119119

120120
// Constant variables that are string literals
121-
// used only by printf will be stored in the second constant buffer.
122-
bool isZebinPrintfStringConst = OpenCLPrintfAnalysis::isPrintfOnlyStringConstant(globalVar);
121+
// used by printf will be stored in the second constant buffer.
122+
bool isZebinPrintfStringConst = OpenCLPrintfAnalysis::isPrintfStringConstant(globalVar);
123123
// Here we follow SPV_EXT_relaxed_printf_string_address_space to relax
124124
// the address space requirement of printf strings and accept
125125
// non-constant address space printf strings. However, we expect it is
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2025 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
; REQUIRES: regkeys
9+
; RUN: igc_opt --typed-pointers -igc-programscope-constant-analysis -igc-serialize-metadata \
10+
; RUN: -S < %s | FileCheck %s
11+
; ------------------------------------------------
12+
; ProgramScopeConstantAnalysis
13+
; ------------------------------------------------
14+
15+
; Test checks that metadata is updated with printf string, while there is reference to this
16+
; string in another global.
17+
18+
; CHECK: !{!"stringConstants",
19+
; CHECK-DAG: !{!"stringConstantsSet{{[[][0-9][]]}}", [3 x i8] addrspace(2)* @str}
20+
21+
@str = internal unnamed_addr addrspace(2) constant [3 x i8] c"A\0A\00", align 1
22+
@ref = addrspace(2) constant [1 x i64] [i64 ptrtoint ([3 x i8] addrspace(2)* @str to i64)]
23+
; decl of opencl printf
24+
declare spir_func i32 @printf(i8 addrspace(2)*, ...)
25+
26+
; Function Attrs: convergent noinline nounwind optnone
27+
define spir_func void @foo() {
28+
%1 = getelementptr inbounds [3 x i8], [3 x i8] addrspace(2)* @str, i64 0, i64 0
29+
%2 = call spir_func i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* %1)
30+
ret void
31+
}

0 commit comments

Comments
 (0)