Coverage Report

Created: 2026-04-01 02:40

/home/runner/work/DirectXShaderCompiler/DirectXShaderCompiler/tools/clang/lib/SPIRV/SpirvModule.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- SpirvModule.cpp - SPIR-V Module Implementation ----------*- C++ -*-==//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
10
#include "clang/SPIRV/SpirvModule.h"
11
#include "clang/SPIRV/SpirvFunction.h"
12
#include "clang/SPIRV/SpirvVisitor.h"
13
14
namespace clang {
15
namespace spirv {
16
17
SpirvModule::SpirvModule()
18
3.22k
    : capabilities({}), extensions({}), extInstSets({}), memoryModel(nullptr),
19
3.22k
      entryPoints({}), executionModes({}), moduleProcesses({}), decorations({}),
20
3.22k
      constants({}), undefs({}), variables({}), functions({}),
21
3.22k
      debugInstructions({}), perVertexInterp(false) {}
22
23
3.22k
SpirvModule::~SpirvModule() {
24
3.22k
  for (auto *cap : capabilities)
25
39.0k
    cap->releaseMemory();
26
3.22k
  for (auto *ext : extensions)
27
14.7k
    ext->releaseMemory();
28
3.22k
  for (auto *set : extInstSets)
29
286
    set->releaseMemory();
30
3.22k
  if (memoryModel)
31
2.92k
    memoryModel->releaseMemory();
32
3.22k
  for (auto *entry : entryPoints)
33
3.05k
    entry->releaseMemory();
34
3.22k
  for (auto *exec : executionModes)
35
3.48k
    exec->releaseMemory();
36
3.22k
  for (auto *str : constStrings)
37
242
    str->releaseMemory();
38
3.22k
  for (auto *d : sources)
39
3.38k
    d->releaseMemory();
40
3.22k
  for (auto *mp : moduleProcesses)
41
20
    mp->releaseMemory();
42
3.22k
  for (auto *decoration : decorations)
43
14.3k
    decoration->releaseMemory();
44
3.22k
  for (auto *constant : constants)
45
57.5k
    constant->releaseMemory();
46
3.22k
  for (auto *undef : undefs)
47
70
    undef->releaseMemory();
48
3.22k
  for (auto *var : variables)
49
11.5k
    var->releaseMemory();
50
3.22k
  for (auto *di : debugInstructions)
51
2.59k
    di->releaseMemory();
52
3.22k
  for (auto *f : allFunctions)
53
8.02k
    f->~SpirvFunction();
54
3.22k
}
55
56
24.6k
bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
57
  // Note: It is debatable whether reverse order of visiting the module should
58
  // reverse everything in this method. For the time being, we just reverse the
59
  // order of the function visitors, and keeping everything else the same.
60
  // For example, it is not clear what the value would be of vising the last
61
  // function first. We can update this methodology if needed.
62
63
24.6k
  if (!visitor->visit(this, Visitor::Phase::Init))
64
3.65k
    return false;
65
66
20.9k
  if (reverseOrder) {
67
    // Reverse order of a SPIR-V module.
68
69
    // Our transformations do not cross function bounaries, therefore the order
70
    // of visiting functions is not important.
71
21.0k
    for (auto iter = functions.rbegin(); iter != functions.rend(); 
++iter15.2k
) {
72
15.2k
      auto *fn = *iter;
73
15.2k
      if (!fn->invokeVisitor(visitor, reverseOrder))
74
0
        return false;
75
15.2k
    }
76
77
5.77k
    for (auto iter = debugInstructions.rbegin();
78
9.87k
         iter != debugInstructions.rend(); 
++iter4.10k
) {
79
4.10k
      auto *debugInstruction = *iter;
80
4.10k
      if (!debugInstruction->invokeVisitor(visitor))
81
0
        return false;
82
4.10k
    }
83
84
27.8k
    
for (auto iter = variables.rbegin(); 5.77k
iter != variables.rend();
++iter22.1k
) {
85
22.1k
      auto *var = *iter;
86
22.1k
      if (!var->invokeVisitor(visitor))
87
0
        return false;
88
22.1k
    }
89
90
106k
    
for (auto iter = constants.rbegin(); 5.77k
iter != constants.rend();
++iter100k
) {
91
100k
      auto *constant = *iter;
92
100k
      if (!constant->invokeVisitor(visitor))
93
0
        return false;
94
100k
    }
95
96
5.86k
    
for (auto iter = undefs.rbegin(); 5.77k
iter != undefs.rend();
++iter92
) {
97
92
      auto *undef = *iter;
98
92
      if (!undef->invokeVisitor(visitor))
99
0
        return false;
100
92
    }
101
102
    // Since SetVector doesn't have 'rbegin()' and 'rend()' methods, we use
103
    // manual indexing.
104
34.2k
    
for (auto decorIndex = decorations.size(); 5.77k
decorIndex > 0;
--decorIndex28.4k
) {
105
28.4k
      auto *decoration = decorations[decorIndex - 1];
106
28.4k
      if (!decoration->invokeVisitor(visitor))
107
0
        return false;
108
28.4k
    }
109
110
5.81k
    
for (auto iter = moduleProcesses.rbegin(); 5.77k
iter != moduleProcesses.rend();
111
5.77k
         
++iter40
) {
112
40
      auto *moduleProcess = *iter;
113
40
      if (!moduleProcess->invokeVisitor(visitor))
114
0
        return false;
115
40
    }
116
117
5.77k
    if (!sources.empty())
118
11.8k
      
for (auto iter = sources.rbegin(); 5.77k
iter != sources.rend();
++iter6.10k
) {
119
6.10k
        auto *source = *iter;
120
6.10k
        if (!source->invokeVisitor(visitor))
121
0
          return false;
122
6.10k
      }
123
124
6.24k
    
for (auto iter = constStrings.rbegin(); 5.77k
iter != constStrings.rend();
125
5.77k
         
++iter472
) {
126
472
      if (!(*iter)->invokeVisitor(visitor))
127
0
        return false;
128
472
    }
129
130
12.3k
    
for (auto iter = executionModes.rbegin(); 5.77k
iter != executionModes.rend();
131
6.55k
         ++iter) {
132
6.55k
      auto *execMode = *iter;
133
6.55k
      if (!execMode->invokeVisitor(visitor))
134
0
        return false;
135
6.55k
    }
136
137
11.8k
    
for (auto iter = entryPoints.rbegin(); 5.77k
iter != entryPoints.rend();
++iter6.05k
) {
138
6.05k
      auto *entryPoint = *iter;
139
6.05k
      if (!entryPoint->invokeVisitor(visitor))
140
0
        return false;
141
6.05k
    }
142
143
5.77k
    if (!memoryModel->invokeVisitor(visitor))
144
0
      return false;
145
146
6.22k
    
for (auto iter = extInstSets.rbegin(); 5.77k
iter != extInstSets.rend();
++iter450
) {
147
450
      auto *extInstSet = *iter;
148
450
      if (!extInstSet->invokeVisitor(visitor))
149
0
        return false;
150
450
    }
151
152
    // Since SetVector doesn't have 'rbegin()' and 'rend()' methods, we use
153
    // manual indexing.
154
20.5k
    
for (auto extIndex = extensions.size(); 5.77k
extIndex > 0;
--extIndex14.7k
) {
155
14.7k
      auto *extension = extensions[extIndex - 1];
156
14.7k
      if (!extension->invokeVisitor(visitor))
157
0
        return false;
158
14.7k
    }
159
160
    // Since SetVector doesn't have 'rbegin()' and 'rend()' methods, we use
161
    // manual indexing.
162
44.9k
    
for (auto capIndex = capabilities.size(); 5.77k
capIndex > 0;
--capIndex39.1k
) {
163
39.1k
      auto *capability = capabilities[capIndex - 1];
164
39.1k
      if (!capability->invokeVisitor(visitor))
165
0
        return false;
166
39.1k
    }
167
5.77k
  }
168
  // Traverse the regular order of a SPIR-V module.
169
15.1k
  else {
170
15.1k
    for (auto *cap : capabilities)
171
119k
      if (!cap->invokeVisitor(visitor))
172
0
        return false;
173
174
15.1k
    for (auto ext : extensions)
175
46.1k
      if (!ext->invokeVisitor(visitor))
176
0
        return false;
177
178
15.1k
    for (auto extInstSet : extInstSets)
179
1.33k
      if (!extInstSet->invokeVisitor(visitor))
180
0
        return false;
181
182
15.1k
    if (!memoryModel->invokeVisitor(visitor))
183
0
      return false;
184
185
15.1k
    for (auto entryPoint : entryPoints)
186
15.9k
      if (!entryPoint->invokeVisitor(visitor))
187
0
        return false;
188
189
15.1k
    for (auto execMode : executionModes)
190
17.4k
      if (!execMode->invokeVisitor(visitor))
191
0
        return false;
192
193
15.1k
    for (auto *str : constStrings)
194
1.46k
      if (!str->invokeVisitor(visitor))
195
0
        return false;
196
197
15.1k
    if (!sources.empty())
198
15.1k
      for (auto *source : sources)
199
16.1k
        if (!source->invokeVisitor(visitor))
200
0
          return false;
201
202
15.1k
    for (auto moduleProcess : moduleProcesses)
203
100
      if (!moduleProcess->invokeVisitor(visitor))
204
0
        return false;
205
206
15.1k
    for (auto decoration : decorations)
207
73.7k
      if (!decoration->invokeVisitor(visitor))
208
0
        return false;
209
210
15.1k
    for (auto constant : constants)
211
285k
      if (!constant->invokeVisitor(visitor))
212
0
        return false;
213
214
15.1k
    for (auto undef : undefs)
215
252
      if (!undef->invokeVisitor(visitor))
216
0
        return false;
217
218
15.1k
    for (auto var : variables)
219
58.7k
      if (!var->invokeVisitor(visitor))
220
0
        return false;
221
222
30.2k
    
for (size_t i = 0; 15.1k
i < debugInstructions.size();
i++15.0k
)
223
15.0k
      if (!debugInstructions[i]->invokeVisitor(visitor))
224
0
        return false;
225
226
15.1k
    for (auto fn : functions)
227
40.8k
      if (!fn->invokeVisitor(visitor, reverseOrder))
228
0
        return false;
229
15.1k
  }
230
231
20.9k
  if (!visitor->visit(this, Visitor::Phase::Done))
232
0
    return false;
233
234
20.9k
  return true;
235
20.9k
}
236
237
7.94k
void SpirvModule::addFunctionToListOfSortedModuleFunctions(SpirvFunction *fn) {
238
7.94k
  assert(fn && "cannot add null function to the module");
239
7.94k
  functions.push_back(fn);
240
7.94k
}
241
242
8.02k
void SpirvModule::addFunction(SpirvFunction *fn) {
243
8.02k
  assert(fn && "cannot add null function to the module");
244
8.02k
  allFunctions.insert(fn);
245
8.02k
}
246
247
89.4k
bool SpirvModule::addCapability(SpirvCapability *cap) {
248
89.4k
  assert(cap && "cannot add null capability to the module");
249
89.4k
  return capabilities.insert(cap);
250
89.4k
}
251
252
2.87k
bool SpirvModule::hasCapability(SpirvCapability &cap) {
253
2.87k
  return capabilities.count(&cap) != 0;
254
2.87k
}
255
256
2.92k
void SpirvModule::setMemoryModel(SpirvMemoryModel *model) {
257
2.92k
  assert(model && "cannot set a null memory model");
258
2.92k
  if (memoryModel)
259
0
    memoryModel->releaseMemory();
260
2.92k
  memoryModel = model;
261
2.92k
}
262
263
38
bool SpirvModule::promoteAddressingModel(spv::AddressingModel addrModel) {
264
38
  assert(memoryModel && "base memory model must be set first");
265
76
  auto getPriority = [](spv::AddressingModel am) -> int {
266
76
    switch (am) {
267
0
    default:
268
0
      assert(false && "unknown addressing model");
269
0
      return 0;
270
38
    case spv::AddressingModel::Logical:
271
38
      return 0;
272
0
    case spv::AddressingModel::Physical32:
273
0
      return 1;
274
0
    case spv::AddressingModel::Physical64:
275
0
      return 2;
276
38
    case spv::AddressingModel::PhysicalStorageBuffer64:
277
38
      return 3;
278
76
    }
279
76
  };
280
281
38
  int current = getPriority(memoryModel->getAddressingModel());
282
38
  int pending = getPriority(addrModel);
283
284
38
  if (pending > current) {
285
38
    memoryModel->setAddressingModel(addrModel);
286
38
    return true;
287
38
  } else {
288
0
    return false;
289
0
  }
290
38
}
291
292
3.05k
void SpirvModule::addEntryPoint(SpirvEntryPoint *ep) {
293
3.05k
  assert(ep && "cannot add null as an entry point");
294
3.05k
  entryPoints.push_back(ep);
295
3.05k
}
296
297
SpirvExecutionModeBase *
298
SpirvModule::findExecutionMode(SpirvFunction *entryPoint,
299
3.73k
                               spv::ExecutionMode em) {
300
5.93k
  for (SpirvExecutionModeBase *cem : executionModes) {
301
5.93k
    if (cem->getEntryPoint() != entryPoint)
302
3.98k
      continue;
303
1.95k
    if (cem->getExecutionMode() != em)
304
1.70k
      continue;
305
248
    return cem;
306
1.95k
  }
307
3.48k
  return nullptr;
308
3.73k
}
309
310
3.48k
void SpirvModule::addExecutionMode(SpirvExecutionModeBase *em) {
311
3.48k
  assert(em && "cannot add null execution mode");
312
3.48k
  executionModes.push_back(em);
313
3.48k
}
314
315
33.0k
bool SpirvModule::addExtension(SpirvExtension *ext) {
316
33.0k
  assert(ext && "cannot add null extension");
317
33.0k
  return extensions.insert(ext);
318
33.0k
}
319
320
286
void SpirvModule::addExtInstSet(SpirvExtInstImport *set) {
321
286
  assert(set && "cannot add null extended instruction set");
322
286
  extInstSets.push_back(set);
323
286
}
324
325
6.98k
SpirvExtInstImport *SpirvModule::getExtInstSet(llvm::StringRef name) {
326
  // We expect very few (usually 1) extended instruction sets to exist in the
327
  // module, so this is not expensive.
328
6.98k
  auto found = std::find_if(extInstSets.begin(), extInstSets.end(),
329
7.23k
                            [name](const SpirvExtInstImport *set) {
330
7.23k
                              return set->getExtendedInstSetName() == name;
331
7.23k
                            });
332
333
6.98k
  if (found != extInstSets.end())
334
6.69k
    return *found;
335
336
286
  return nullptr;
337
6.98k
}
338
339
10.7k
void SpirvModule::addVariable(SpirvVariableLike *var) {
340
10.7k
  assert(var && "cannot add null variable to the module");
341
10.7k
  variables.push_back(var);
342
10.7k
}
343
344
814
void SpirvModule::addVariable(SpirvVariableLike *var, SpirvInstruction *pos) {
345
814
  assert(var && "cannot add null variable to the module");
346
814
  auto location = std::find(variables.begin(), variables.end(), pos);
347
814
  variables.insert(location, var);
348
814
}
349
350
14.3k
void SpirvModule::addDecoration(SpirvDecoration *decor) {
351
14.3k
  assert(decor && "cannot add null decoration to the module");
352
14.3k
  decorations.insert(decor);
353
14.3k
}
354
355
57.5k
void SpirvModule::addConstant(SpirvConstant *constant) {
356
57.5k
  assert(constant);
357
57.5k
  constants.push_back(constant);
358
57.5k
}
359
360
70
void SpirvModule::addUndef(SpirvUndef *undef) {
361
70
  assert(undef);
362
70
  undefs.push_back(undef);
363
70
}
364
365
242
void SpirvModule::addString(SpirvString *str) {
366
242
  assert(str);
367
242
  constStrings.push_back(str);
368
242
}
369
370
3.38k
void SpirvModule::addSource(SpirvSource *src) {
371
3.38k
  assert(src);
372
3.38k
  sources.push_back(src);
373
3.38k
}
374
375
2.60k
void SpirvModule::addDebugInfo(SpirvDebugInstruction *info) {
376
2.60k
  assert(info);
377
2.60k
  debugInstructions.push_back(info);
378
2.60k
}
379
380
20
void SpirvModule::addModuleProcessed(SpirvModuleProcessed *p) {
381
20
  assert(p);
382
20
  moduleProcesses.push_back(p);
383
20
}
384
385
36
SpirvDebugCompilationUnit *SpirvModule::getDebugCompilationUnit() {
386
36
  SpirvDebugCompilationUnit *unit = debugCompilationUnit;
387
36
  assert(unit && "null DebugCompilationUnit");
388
36
  return unit;
389
36
}
390
391
122
void SpirvModule::setDebugCompilationUnit(SpirvDebugCompilationUnit *unit) {
392
122
  assert(unit);
393
122
  debugCompilationUnit = unit;
394
122
}
395
396
} // end namespace spirv
397
} // end namespace clang