File: ProcessBICodeAssumption.cpp

package info (click to toggle)
intel-graphics-compiler2 2.22.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 107,676 kB
  • sloc: cpp: 809,645; lisp: 288,070; ansic: 16,397; python: 4,010; yacc: 2,588; lex: 1,666; pascal: 314; sh: 186; makefile: 38
file content (167 lines) | stat: -rw-r--r-- 5,489 bytes parent folder | download
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*========================== begin_copyright_notice ============================

Copyright (C) 2025 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

#include "Compiler/Optimizer/OpenCLPasses/ProcessBICodeAssumption/ProcessBICodeAssumption.hpp"
#include "Compiler/IGCPassSupport.h"

#include "common/LLVMWarningsPush.hpp"
#include <llvm/IR/Function.h>
#include <llvm/IR/InstVisitor.h>
#include <llvm/IR/PatternMatch.h>
#include "common/LLVMWarningsPop.hpp"

#include "Compiler/CodeGenPublic.h"

using namespace llvm;
using namespace llvm::PatternMatch;
using namespace IGC;

// OpenCL standard defines built-in variables like get_global_id as size_t, which translates to i64, but in reality
// many workloads use values that fit in i32. This pass checks if there are assumptions on built-in variables and adds
// trunc/zext intructions to reflect that the upper 32 bits are not used. This helps instcombine to optimize code after
// BIImport.
class ProcessBICodeAssumption : public llvm::FunctionPass, public llvm::InstVisitor<ProcessBICodeAssumption> {
public:
  static char ID;
  ProcessBICodeAssumption();

  virtual llvm::StringRef getPassName() const override { return "ProcessBICodeAssumption"; }

  virtual bool runOnFunction(Function &F) override;
  void visitCallInst(CallInst &I);

private:
  bool matchCmp(ICmpInst::Predicate Pred, ConstantInt *CI);
  bool matchBuiltin(Instruction *I);
  void matchVectorPattern(Instruction *I);

  SmallPtrSet<Instruction *, 8> ToTruncate;
};

ProcessBICodeAssumption::ProcessBICodeAssumption() : FunctionPass(ID) {
  initializeProcessBICodeAssumptionPass(*PassRegistry::getPassRegistry());
}

bool ProcessBICodeAssumption::runOnFunction(Function &F) {

  ToTruncate.clear();
  visit(F);

  if (ToTruncate.empty())
    return false;

  // Insert trunc/zext for each matched builtin call.
  for (auto *I : ToTruncate) {

    IRBuilder<> Builder(I);
    Builder.SetInsertPoint(I->getNextNode());

    auto Trunc = Builder.CreateTrunc(I, Builder.getInt32Ty());
    auto Zext = Builder.CreateZExt(Trunc, Builder.getInt64Ty());

    for (auto It = I->use_begin(), E = I->use_end(); It != E; ) {
      auto Use = It++;
      if (Use->getUser() != Trunc)
        Use->set(Zext);
    }
  }

  return true;
}

void ProcessBICodeAssumption::visitCallInst(CallInst &CI) {

  Instruction *I = nullptr;
  ICmpInst::Predicate Pred;
  ConstantInt *Const = nullptr;

  // Look for assume:
  //   %9 = icmp ult i64 %8, 2147483648
  //   call void @llvm.assume(i1 %9)
  if (!match(&CI, m_Intrinsic<Intrinsic::assume>(m_ICmp(Pred, m_Instruction(I), m_ConstantInt(Const)))))
    return;

  if (!matchCmp(Pred, Const))
    return;

  if (matchBuiltin(I)) {
    ToTruncate.insert(I);
    return;
  }

  matchVectorPattern(I);
}

// Look for pattern with insertelement/extractelement:
//   %1 = call spir_func i64 @_Z33__spirv_BuiltInGlobalInvocationIdi(i32 0)
//   %2 = insertelement <3 x i64> undef, i64 %1, i32 0
//   %3 = call spir_func i64 @_Z33__spirv_BuiltInGlobalInvocationIdi(i32 1)
//   %4 = insertelement <3 x i64> %2, i64 %3, i32 1
//   %5 = call spir_func i64 @_Z33__spirv_BuiltInGlobalInvocationIdi(i32 2)
//   %6 = insertelement <3 x i64> %4, i64 %5, i32 2
//   %7 = extractelement <3 x i64> %6, i32 0
void ProcessBICodeAssumption::matchVectorPattern(Instruction *I) {

  Instruction *EE = I;

  // Optional select
  //   %7 = extractelement <3 x i64> %6, i32 0
  //   %8 = select i1 true, i64 %7, i64 0
  if (match(EE, m_Select(m_One(), m_Instruction(I), m_Value())))
    EE = I;

  Value *IE = nullptr, *NextIE = nullptr;
  ConstantInt *EConst = nullptr, *IConst = nullptr;

  if (!match(EE, m_ExtractElt(m_Value(IE), m_ConstantInt(EConst))))
    return;

  while (match(IE, m_InsertElt(m_Value(NextIE), m_Instruction(I), m_ConstantInt(IConst)))) {
    if (IConst->getZExtValue() == EConst->getZExtValue()) {
      if (matchBuiltin(I))
        ToTruncate.insert(I);
      return;
    }
    IE = NextIE;
  }
}

bool ProcessBICodeAssumption::matchCmp(ICmpInst::Predicate Pred, ConstantInt *CI) {
  switch (Pred) {
  case ICmpInst::ICMP_ULE:
    return CI->getZExtValue() <= llvm::APInt::getMaxValue(32).getZExtValue();
  case ICmpInst::ICMP_ULT:
    return CI->getZExtValue() <= llvm::APInt::getMaxValue(32).getZExtValue() + 1;
  case ICmpInst::ICMP_SLE:
    return CI->getZExtValue() <= llvm::APInt::getSignedMaxValue(32).getZExtValue();
  case ICmpInst::ICMP_SLT:
    return CI->getZExtValue() <= llvm::APInt::getSignedMaxValue(32).getZExtValue() + 1;
  default:
    return false;
  }
}

bool ProcessBICodeAssumption::matchBuiltin(Instruction *I) {
  if (auto CI = dyn_cast<CallInst>(I)) {
    return CI->getCalledFunction()->getName() == "_Z33__spirv_BuiltInGlobalInvocationIdi" ||
           CI->getCalledFunction()->getName() == "_Z29__spirv_BuiltInGlobalLinearIdv";
  }
  return false;
}

// Register pass to igc-opt
#define PASS_FLAG "igc-process-bi-code-assumption"
#define PASS_DESCRIPTION "Processes code assumptions assigned to builtin variables"
#define PASS_CFG_ONLY false
#define PASS_ANALYSIS false
IGC_INITIALIZE_PASS_BEGIN(ProcessBICodeAssumption, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
IGC_INITIALIZE_PASS_END(ProcessBICodeAssumption, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)

char ProcessBICodeAssumption::ID = 0;

FunctionPass *IGC::createProcessBICodeAssumptionPass() { return new ProcessBICodeAssumption(); }