-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add debug option to inject printf with pointer and type on every det…
…ected cast This commit introduces a new debug feature that inserts a printf statement before load and store operations. The printf outputs the pointer value and the type that is being loaded or stored. This feature is controlled by a new debug flag.
- Loading branch information
Showing
9 changed files
with
245 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
IGC/Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/InjectPrintf.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/*========================== begin_copyright_notice ============================ | ||
Copyright (C) 2024 Intel Corporation | ||
SPDX-License-Identifier: MIT | ||
============================= end_copyright_notice ===========================*/ | ||
|
||
#include "InjectPrintf.hpp" | ||
#include "llvm/IR/IRBuilder.h" | ||
#include <common/igc_regkeys.hpp> | ||
|
||
#include "common/LLVMWarningsPush.hpp" | ||
#include "common/LLVMWarningsPop.hpp" | ||
#include "Compiler/IGCPassSupport.h" | ||
|
||
|
||
using namespace IGC; | ||
using namespace llvm; | ||
|
||
char InjectPrintf::ID = 0; | ||
|
||
#define PASS_FLAG "inject-printf" | ||
#define PASS_DESCRIPTION "Inject printf before load and store operations for ptr Pass." | ||
#define PASS_CFG_ONLY false | ||
#define PASS_ANALYSIS false | ||
IGC_INITIALIZE_PASS_BEGIN(InjectPrintf, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) | ||
IGC_INITIALIZE_PASS_END(InjectPrintf, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) | ||
|
||
enum class InjectPrintfFlagType { | ||
#define INJECT_PRINTF_OPTION(Name, Val) Name = Val, | ||
#include "igc_regkeys_enums_defs.h" | ||
INJECT_PRINTF_OPTIONS | ||
#undef INJECT_PRINTF_OPTION | ||
#undef INJECT_PRINTF_OPTIONS | ||
}; | ||
|
||
InjectPrintf::InjectPrintf() : FunctionPass(ID) { | ||
initializeInjectPrintfPass(*PassRegistry::getPassRegistry()); | ||
} | ||
|
||
GlobalVariable* InjectPrintf::createGlobalFormatStr(Module* Module, LLVMContext& Context) { | ||
IGC_ASSERT(Module != nullptr); | ||
|
||
const char* FormatStrLiteral = "Pointer: %p, Type: %s\n"; | ||
size_t MaxLength = 256; | ||
size_t FormatStrSize = strnlen(FormatStrLiteral, MaxLength) + 1; | ||
|
||
GlobalVariable* FormatStrGlobal = new GlobalVariable( | ||
*Module, | ||
ArrayType::get(Type::getInt8Ty(Context), FormatStrSize), | ||
true, | ||
GlobalValue::InternalLinkage, | ||
ConstantDataArray::getString(Context, FormatStrLiteral, true), | ||
"", | ||
nullptr, | ||
GlobalValue::ThreadLocalMode::NotThreadLocal, | ||
2 | ||
); | ||
FormatStrGlobal->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); | ||
|
||
return FormatStrGlobal; | ||
} | ||
|
||
Value* InjectPrintf::createGEP(GlobalVariable* GlobalVariable, Instruction* InsertBefore) { | ||
IGC_ASSERT(GlobalVariable != nullptr); | ||
IGC_ASSERT(InsertBefore != nullptr); | ||
|
||
LLVMContext& Context = GlobalVariable->getParent()->getContext(); | ||
const auto Zero = ConstantInt::getSigned(Type::getInt32Ty(Context), 0); | ||
auto Result = GetElementPtrInst::Create( | ||
GlobalVariable->getValueType(), | ||
GlobalVariable, | ||
{ Zero, Zero }, | ||
"", | ||
InsertBefore | ||
); | ||
Result->setIsInBounds(true); | ||
return Result; | ||
} | ||
|
||
void InjectPrintf::insertPrintf(IRBuilder<>& Builder, FunctionCallee PrintfFunc, GlobalVariable* FormatStrGlobal, Instruction* Inst, Value* PointerOperand, Type* ValueType) { | ||
IGC_ASSERT(FormatStrGlobal != nullptr); | ||
IGC_ASSERT(Inst != nullptr); | ||
IGC_ASSERT(PointerOperand != nullptr); | ||
IGC_ASSERT(ValueType != nullptr); | ||
|
||
Builder.SetInsertPoint(Inst); | ||
Value* FormatStr = createGEP(FormatStrGlobal, Inst); | ||
std::string TypeStr; | ||
raw_string_ostream RSO(TypeStr); | ||
ValueType->print(RSO); | ||
Value* TypeStrGlobal = Builder.CreateGlobalStringPtr(RSO.str()); | ||
Builder.CreateCall(PrintfFunc, { FormatStr, PointerOperand, TypeStrGlobal }); | ||
} | ||
|
||
bool InjectPrintf::runOnFunction(Function& F) { | ||
LLVMContext& Context = F.getContext(); | ||
Module* Module = F.getParent(); | ||
if (!Module) { | ||
errs() << "Error: Module is null\n"; | ||
return false; | ||
} | ||
|
||
IRBuilder<> Builder(Context); | ||
GlobalVariable* FormatStrGlobal = createGlobalFormatStr(Module, Context); | ||
|
||
FunctionCallee PrintfFunc = Module->getOrInsertFunction( | ||
"printf", | ||
FunctionType::get( | ||
IntegerType::getInt32Ty(Context), | ||
PointerType::get(Type::getInt8Ty(Context), 2), | ||
true | ||
) | ||
); | ||
|
||
auto InjectPrintfFlag = static_cast<InjectPrintfFlagType>(IGC_GET_FLAG_VALUE(InjectPrintfFlag)); | ||
for (auto& BB : F) { | ||
for (auto& I : BB) { | ||
if (auto* Load = dyn_cast<LoadInst>(&I)) { | ||
if (InjectPrintfFlag == InjectPrintfFlagType::InjectPrintfLoads || InjectPrintfFlag == InjectPrintfFlagType::InjectPrintfLoadsAndStores) { | ||
insertPrintf(Builder, PrintfFunc, FormatStrGlobal, Load, Load->getPointerOperand(), Load->getType()); | ||
} | ||
} | ||
if (auto* Store = dyn_cast<StoreInst>(&I)) { | ||
if (InjectPrintfFlag == InjectPrintfFlagType::InjectPrintfStores || InjectPrintfFlag == InjectPrintfFlagType::InjectPrintfLoadsAndStores) { | ||
insertPrintf(Builder, PrintfFunc, FormatStrGlobal, Store, Store->getPointerOperand(), Store->getValueOperand()->getType()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return true; | ||
} |
40 changes: 40 additions & 0 deletions
40
IGC/Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/InjectPrintf.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/*========================== begin_copyright_notice ============================ | ||
Copyright (C) 2024 Intel Corporation | ||
SPDX-License-Identifier: MIT | ||
============================= end_copyright_notice ===========================*/ | ||
|
||
#ifndef INJECT_PRINTF_HPP | ||
#define INJECT_PRINTF_HPP | ||
|
||
#include "llvm/IR/Function.h" | ||
#include "llvm/Pass.h" | ||
#include "llvm/IR/IRBuilder.h" | ||
|
||
namespace IGC | ||
{ | ||
class InjectPrintf : public llvm::FunctionPass | ||
{ | ||
public: | ||
static char ID; | ||
|
||
InjectPrintf(); | ||
~InjectPrintf() {} | ||
|
||
virtual llvm::StringRef getPassName() const override | ||
{ | ||
return "InjectPrintf"; | ||
} | ||
|
||
bool runOnFunction(llvm::Function& F) override; | ||
|
||
private: | ||
llvm::GlobalVariable* createGlobalFormatStr(llvm::Module* module, llvm::LLVMContext& context); | ||
llvm::Value* createGEP(llvm::GlobalVariable* globalVariable, llvm::Instruction* insertBefore); | ||
void insertPrintf(llvm::IRBuilder<>& builder, llvm::FunctionCallee printfFunc, llvm::GlobalVariable* formatStrGlobal, llvm::Instruction* inst, llvm::Value* pointerOperand, llvm::Type* valueType); | ||
}; | ||
} | ||
|
||
#endif // INJECT_PRINTF_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
;=========================== begin_copyright_notice ============================ | ||
; | ||
; Copyright (C) 2024 Intel Corporation | ||
; | ||
; SPDX-License-Identifier: MIT | ||
; | ||
;============================ end_copyright_notice ============================= | ||
; REQUIRES: regkeys | ||
; | ||
; RUN: igc_opt -regkey InjectPrintfFlag=1 --inject-printf -S < %s | FileCheck %s --check-prefix=LOADS | ||
; RUN: igc_opt -regkey InjectPrintfFlag=2 --inject-printf -S < %s | FileCheck %s --check-prefix=STORES | ||
; RUN: igc_opt -regkey InjectPrintfFlag=3 --inject-printf -S < %s | FileCheck %s --check-prefix=LOADS_AND_STORES | ||
; | ||
; ------------------------------------------------ | ||
; InjectPrintf | ||
; ------------------------------------------------ | ||
|
||
@global_var = global i32 0 | ||
|
||
define spir_kernel void @test_function() { | ||
entry: | ||
%ptr = alloca i32, align 4 | ||
%val = load i32, i32* %ptr, align 4 | ||
store i32 %val, i32* @global_var, align 4 | ||
ret void | ||
} | ||
|
||
; LOADS-LABEL: @test_function( | ||
; LOADS: call i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* %0, i32* %ptr, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0)) | ||
; LOADS: load i32, i32* %ptr, align 4 | ||
; LOADS-NOT: call i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* %0, i32* @global_var, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0)) | ||
; LOADS: store i32 %val, i32* @global_var, align 4 | ||
; LOADS: ret void | ||
|
||
; STORES-LABEL: @test_function( | ||
; STORES-NOT: call i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* %0, i32* %ptr, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0)) | ||
; STORES: load i32, i32* %ptr, align 4 | ||
; STORES: call i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* %0, i32* @global_var, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0)) | ||
; STORES: store i32 %val, i32* @global_var, align 4 | ||
; STORES: ret void | ||
|
||
; LOADS_AND_STORES-LABEL: @test_function( | ||
; LOADS_AND_STORES: call i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* %0, i32* %ptr, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0)) | ||
; LOADS_AND_STORES: load i32, i32* %ptr, align 4 | ||
; LOADS_AND_STORES: call i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* %2, i32* @global_var, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @2, i32 0, i32 0)) | ||
; LOADS_AND_STORES: store i32 %val, i32* @global_var, align 4 | ||
; LOADS_AND_STORES: ret void |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters