1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#include "Compiler/Optimizer/OpenCLPasses/UndefinedReferences/UndefinedReferencesPass.hpp"
#include "Compiler/IGCPassSupport.h"
#include "Compiler/CodeGenPublic.h"
#include "common/LLVMWarningsPush.hpp"
#include <llvm/IR/Module.h>
#include <llvm/IR/Function.h>
#include "common/LLVMWarningsPop.hpp"
#include "GenISAIntrinsics/GenIntrinsics.h"
using namespace llvm;
using namespace IGC;
// Register pass to igc-opt
#define PASS_FLAG "undefined-references"
#define PASS_DESCRIPTION "Emit linker warnings to user"
#define PASS_CFG_ONLY false
#define PASS_ANALYSIS true
IGC_INITIALIZE_PASS_BEGIN(UndefinedReferencesPass, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
IGC_INITIALIZE_PASS_END(UndefinedReferencesPass, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
char UndefinedReferencesPass::ID = 0;
UndefinedReferencesPass::UndefinedReferencesPass() : ModulePass(ID)
{
initializeUndefinedReferencesPassPass(*PassRegistry::getPassRegistry());
}
static void ReportUndefinedReference(CodeGenContext *CGC, StringRef name, Value *ctx)
{
std::string message;
message += "undefined reference to `" + name.str() + "'";
CGC->EmitError(message.c_str(), ctx);
}
///////////////////////////////////////////////////////////////////////////////
//
// ExistUndefinedReferencesInModule()
//
// LLVM's linker only does the job of tying together references across modules;
// for LLVM since a declaration in LLVM IR is perfectly valid, it does not make
// sense to check for any remaining undefined references. Call this function
// after linking to determine this. A true return value indicates there are
// undefined references, the errors will be reported to CodeGenContext as they
// are detected.
//
static bool ExistUndefinedReferencesInModule(Module& module, CodeGenContext *CGC)
{
bool foundUndef = false;
Module::global_iterator GVarIter = module.global_begin();
for (; GVarIter != module.global_end();)
{
GlobalVariable* pGVar = &(*GVarIter);
// Increment the iterator before attempting to remove a global variable
GVarIter++;
if ((pGVar->hasAtLeastLocalUnnamedAddr() == false || pGVar->hasNUsesOrMore(1)) &&
(pGVar->hasExternalLinkage() || pGVar->hasCommonLinkage()))
{
continue;
}
if (pGVar->isDeclaration() && pGVar->hasNUsesOrMore(1))
{
ReportUndefinedReference(CGC, pGVar->getName(), pGVar);
foundUndef = true;
}
if (!pGVar->isDeclaration() && pGVar->use_empty())
{
// Remove the declaration
pGVar->eraseFromParent();
}
}
for (auto& F : module)
{
if (F.isDeclaration() && !F.isIntrinsic() && !GenISAIntrinsic::isIntrinsic(&F) && F.hasNUsesOrMore(1))
{
StringRef funcName = F.getName();
if (!funcName.startswith("__builtin_IB") && funcName != "printf" &&
!funcName.startswith("__igcbuiltin_") &&
!funcName.startswith("__translate_sampler_initializer") &&
#if defined(IGC_SCALAR_USE_KHRONOS_SPIRV_TRANSLATOR)
!funcName.startswith("_Z20__spirv_SampledImage") &&
!funcName.startswith("_Z21__spirv_VmeImageINTEL") &&
#else
!funcName.startswith("__builtin_spirv_OpSampledImage") &&
!funcName.startswith("__builtin_spirv_OpVmeImageINTEL") &&
#endif
!F.hasFnAttribute("referenced-indirectly"))
{
ReportUndefinedReference(CGC, funcName, &F);
foundUndef = true;
}
}
}
return foundUndef;
}
bool UndefinedReferencesPass::runOnModule(Module& M)
{
// At this point all references should have been linked to definitions, any
// undefined references should generate errors.
CodeGenContext *CGC = getAnalysis<CodeGenContextWrapper>().getCodeGenContext();
ExistUndefinedReferencesInModule(M, CGC);
return false;
}
|