Skip to content

Commit

Permalink
Add debug option to inject printf with pointer and type on every det…
Browse files Browse the repository at this point in the history
…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
ustachow authored and igcbot committed Nov 19, 2024
1 parent d60a48c commit af7dd19
Show file tree
Hide file tree
Showing 9 changed files with 245 additions and 5 deletions.
4 changes: 3 additions & 1 deletion IGC/AdaptorOCL/UnifyIROCL.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2022 Intel Corporation
Copyright (C) 2017-2024 Intel Corporation
SPDX-License-Identifier: MIT
Expand Down Expand Up @@ -75,6 +75,7 @@ SPDX-License-Identifier: MIT
#include "Compiler/Optimizer/OpenCLPasses/WGFuncs/WGFuncResolution.hpp"
#include "Compiler/Optimizer/OpenCLPasses/AlignmentAnalysis/AlignmentAnalysis.hpp"
#include "Compiler/Optimizer/PreCompiledFuncImport.hpp"
#include "Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/InjectPrintf.hpp"
#include "Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/OpenCLPrintfAnalysis.hpp"
#include "Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/OpenCLPrintfResolution.hpp"
#include "Compiler/Optimizer/OpenCLPasses/AggregateArguments/AggregateArguments.hpp"
Expand Down Expand Up @@ -545,6 +546,7 @@ static void CommonOCLBasedPasses(OpenCLProgramContext* pContext)
// Analysis passes
mpm.add(new WIFuncsAnalysis());
mpm.add(new ImageFuncsAnalysis());
mpm.add(new InjectPrintf());
mpm.add(new OpenCLPrintfAnalysis());
mpm.add(createDeadCodeEliminationPass());
mpm.add(new ProgramScopeConstantAnalysis());
Expand Down
1 change: 1 addition & 0 deletions IGC/Compiler/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,4 @@ void initializeLoopCountAnalysisPass(llvm::PassRegistry&);
void initializeCollectLoopCountPass(llvm::PassRegistry&);
void initializeRemoveLoopDependencyPass(llvm::PassRegistry&);
void initializeResourceLoopUnrollPass(llvm::PassRegistry&);
void initializeInjectPrintfPass(llvm::PassRegistry&);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#=========================== begin_copyright_notice ============================
#
# Copyright (C) 2017-2021 Intel Corporation
# Copyright (C) 2017-2024 Intel Corporation
#
# SPDX-License-Identifier: MIT
#
Expand All @@ -12,12 +12,14 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
set(IGC_BUILD__SRC__OpenCLPrintf
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLPrintfAnalysis.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLPrintfResolution.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/InjectPrintf.cpp"
)
set(IGC_BUILD__SRC__OpenCLPasses_OpenCLPrintf ${IGC_BUILD__SRC__OpenCLPrintf} PARENT_SCOPE)

set(IGC_BUILD__HDR__OpenCLPrintf
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLPrintfAnalysis.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLPrintfResolution.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/InjectPrintf.hpp"
)
set(IGC_BUILD__HDR__OpenCLPasses_OpenCLPrintf ${IGC_BUILD__HDR__OpenCLPrintf} PARENT_SCOPE)

Expand Down
134 changes: 134 additions & 0 deletions IGC/Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/InjectPrintf.cpp
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 IGC/Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/InjectPrintf.hpp
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
47 changes: 47 additions & 0 deletions IGC/Compiler/tests/InjectPrintf/basic.ll
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
3 changes: 2 additions & 1 deletion IGC/common/igc_flags.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2023 Intel Corporation
Copyright (C) 2017-2024 Intel Corporation
SPDX-License-Identifier: MIT
Expand Down Expand Up @@ -470,6 +470,7 @@ DECLARE_IGC_REGKEY(bool, StackOverflowDetection, false, "Inserts checks f
DECLARE_IGC_REGKEY(bool, BufferBoundsChecking, false, "Setting this to 1 (true) enables buffer bounds checking", false)
DECLARE_IGC_REGKEY(DWORD, MinimumValidAddress, 0, "If it's greater than 0, it enables minimal valid address checking where the threshold is the given value (in hex).", false)
DECLARE_IGC_REGKEY(bool, AssignZeroToUndefPhiNodes, false, "Assigns a null value to such a phi node which has an undefined value during emitting vISA", false)
DECLARE_IGC_REGKEY_ENUM(InjectPrintfFlag, 0, "Inject printf debugging flag", INJECT_PRINTF_OPTIONS, true)

DECLARE_IGC_GROUP("IGC Features")
DECLARE_IGC_REGKEY(bool, EnableOCLSIMD16, true, "Enable OCL SIMD16 mode", true)
Expand Down
7 changes: 6 additions & 1 deletion IGC/common/igc_regkeys.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2023 Intel Corporation
Copyright (C) 2017-2024 Intel Corporation
SPDX-License-Identifier: MIT
Expand Down Expand Up @@ -32,6 +32,8 @@ SPDX-License-Identifier: MIT
#define TRIBOOL_OPTION(Name, Val) #Name "=" #Val ","
#define RTMEMORY_STYLE_OPTION(Name, Val) #Name "=" #Val ","

#define INJECT_PRINTF_OPTION(Name, Val) #Name "=" #Val ","

#include "igc_regkeys_enums_defs.h"


Expand All @@ -54,6 +56,9 @@ SPDX-License-Identifier: MIT
#undef RTMEMORY_STYLE_OPTION
#undef RTMEMORY_STYLE_OPTIONS

#undef INJECT_PRINTF_OPTION
#undef INJECT_PRINTF_OPTIONS

#undef DECLARE_IGC_GROUP
#undef DECLARE_IGC_REGKEY_ENUM
#undef DECLARE_IGC_REGKEY_BITMASK
10 changes: 9 additions & 1 deletion IGC/common/igc_regkeys_enums_defs.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*========================== begin_copyright_notice ============================
Copyright (C) 2022-2023 Intel Corporation
Copyright (C) 2022-2024 Intel Corporation
SPDX-License-Identifier: MIT
Expand Down Expand Up @@ -101,3 +101,11 @@ SPDX-License-Identifier: MIT
TRIBOOL_OPTION(Enabled, 1)
#endif // TRIBOOL_OPTION


#ifdef INJECT_PRINTF_OPTION
#define INJECT_PRINTF_OPTIONS \
INJECT_PRINTF_OPTION(InjectPrintfNone, 0)\
INJECT_PRINTF_OPTION(InjectPrintfLoads, 1)\
INJECT_PRINTF_OPTION(InjectPrintfStores, 2)\
INJECT_PRINTF_OPTION(InjectPrintfLoadsAndStores, 3)
#endif // INJECT_PRINTF_OPTION

0 comments on commit af7dd19

Please sign in to comment.