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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
|
// slang-emit-c-like.h
#ifndef SLANG_EMIT_C_LIKE_H
#define SLANG_EMIT_C_LIKE_H
#include "../core/slang-basic.h"
#include "slang-compiler.h"
#include "slang-emit-base.h"
#include "slang-emit-precedence.h"
#include "slang-emit-source-writer.h"
#include "slang-ir-insts.h"
#include "slang-ir-restructure.h"
#include "slang-ir.h"
namespace Slang
{
class CLikeSourceEmitter : public SourceEmitterBase
{
public:
enum class EmitLayoutSemanticOption
{
kPreType,
kPostType
};
struct Desc
{
CodeGenContext* codeGenContext = nullptr;
/// The stage for the entry point we are being asked to compile
Stage entryPointStage = Stage::Unknown;
/// The "effective" profile that is being used to emit code,
/// combining information from the target and entry point.
Profile effectiveProfile = Profile::RawEnum::Unknown;
/// The source writer to use
SourceWriter* sourceWriter = nullptr;
};
enum
{
kThreadGroupAxisCount = 3,
};
typedef unsigned int ESemanticMask;
enum
{
kESemanticMask_None = 0,
kESemanticMask_NoPackOffset = 1 << 0,
kESemanticMask_Default = kESemanticMask_NoPackOffset,
};
/// A C-style declarator, used for emitting types and declarations.
///
/// A C-style declaration typically has a *type specifier* (like
/// `int` or `MyType`) and a *declarator* (like `myVar` or
/// `myArray[]` or `*myPtr`).
///
/// The type of a declaration depends on both the type specifier
/// the declarator, and we already have logic to "unwrap" the
/// syntax of a declarator as part of the parser.
///
/// A `DeclaratorInfo` is used for the inverse process: taking
/// a complete type and splitting out the parts that need to be
/// handled as declarators when emitting code in a C-like language.
///
struct DeclaratorInfo
{
public:
enum class Flavor
{
Name,
Ptr,
Ref,
SizedArray,
UnsizedArray,
LiteralSizedArray,
Attributed,
};
Flavor flavor;
protected:
DeclaratorInfo(Flavor flavor)
: flavor(flavor)
{
}
};
/// A simple declarator that only includes a name
struct NameDeclaratorInfo : DeclaratorInfo
{
const StringSliceLoc* nameAndLoc;
NameDeclaratorInfo(StringSliceLoc const* nameAndLoc)
: DeclaratorInfo(Flavor::Name), nameAndLoc(nameAndLoc)
{
}
};
/// A "chained" declarator that may a nested declarator.
struct ChainedDeclaratorInfo : DeclaratorInfo
{
DeclaratorInfo* next = nullptr;
protected:
ChainedDeclaratorInfo(Flavor flavor, DeclaratorInfo* next)
: DeclaratorInfo(flavor), next(next)
{
}
};
struct PtrDeclaratorInfo : ChainedDeclaratorInfo
{
PtrDeclaratorInfo(DeclaratorInfo* next)
: ChainedDeclaratorInfo(Flavor::Ptr, next)
{
}
};
struct RefDeclaratorInfo : ChainedDeclaratorInfo
{
RefDeclaratorInfo(DeclaratorInfo* next)
: ChainedDeclaratorInfo(Flavor::Ref, next)
{
}
};
struct SizedArrayDeclaratorInfo : ChainedDeclaratorInfo
{
IRInst* elementCount;
SizedArrayDeclaratorInfo(DeclaratorInfo* next, IRInst* elementCount)
: ChainedDeclaratorInfo(Flavor::SizedArray, next), elementCount(elementCount)
{
}
};
struct UnsizedArrayDeclaratorInfo : ChainedDeclaratorInfo
{
UnsizedArrayDeclaratorInfo(DeclaratorInfo* next)
: ChainedDeclaratorInfo(Flavor::UnsizedArray, next)
{
}
};
struct LiteralSizedArrayDeclaratorInfo : ChainedDeclaratorInfo
{
IRIntegerValue elementCount;
LiteralSizedArrayDeclaratorInfo(DeclaratorInfo* next, IRIntegerValue elementCount)
: ChainedDeclaratorInfo(Flavor::LiteralSizedArray, next), elementCount(elementCount)
{
}
};
struct AttributedDeclaratorInfo : ChainedDeclaratorInfo
{
AttributedDeclaratorInfo(DeclaratorInfo* next, IRInst* instWithAttributes)
: ChainedDeclaratorInfo(Flavor::Attributed, next)
, instWithAttributes(instWithAttributes)
{
}
IRInst* instWithAttributes;
};
struct FuncTypeDeclaratorInfo : ChainedDeclaratorInfo
{
FuncTypeDeclaratorInfo(DeclaratorInfo* next, IRFuncType* funcTypeInst)
: ChainedDeclaratorInfo(Flavor::Attributed, next), funcType(funcTypeInst)
{
}
IRFuncType* funcType;
};
struct ComputeEmitActionsContext;
// An action to be performed during code emit.
struct EmitAction
{
enum Level
{
ForwardDeclaration,
Definition,
};
Level level;
IRInst* inst;
};
// A chain of variables to use for emitting semantic/layout info
struct EmitVarChain
{
IRVarLayout* varLayout;
EmitVarChain* next;
EmitVarChain()
: varLayout(nullptr), next(nullptr)
{
}
EmitVarChain(IRVarLayout* varLayout)
: varLayout(varLayout), next(nullptr)
{
}
EmitVarChain(IRVarLayout* varLayout, EmitVarChain* next)
: varLayout(varLayout), next(next)
{
}
};
/// Must be called before used
virtual SlangResult init();
/// Ctor
CLikeSourceEmitter(const Desc& desc);
/// Get the source manager
SourceManager* getSourceManager() { return m_codeGenContext->getSourceManager(); }
/// Get the source writer used
SourceWriter* getSourceWriter() const { return m_writer; }
/// Get the diagnostic sink
DiagnosticSink* getSink() { return m_codeGenContext->getSink(); }
/// Diagnose a diagnostic only once per diagnostic ID and all parameters
template<typename... Args>
void diagnoseOnce(SourceLoc loc, DiagnosticInfo const& diagnostic, Args&&... args)
{
// For diagnostics with parameters, we'll use all parameters to create a unique key
// This prevents duplicate diagnostics while allowing different parameter combinations
if constexpr (sizeof...(args) > 0)
{
String key = String(diagnostic.id);
((key = key + "|" + String(args)), ...); // Fold expression to append all args
if (!m_reportedDiagnosticKeys.add(key))
return;
}
else
{
// For diagnostics without parameters, just use the ID
if (!m_reportedDiagnosticIds.add(diagnostic.id))
return;
}
// Report the diagnostic
getSink()->diagnose(loc, diagnostic, std::forward<Args>(args)...);
}
/// Get the code gen target
CodeGenTarget getTarget() { return m_target; }
/// Get the source style
SLANG_FORCE_INLINE SourceLanguage getSourceLanguage() const { return m_sourceLanguage; }
void noteInternalErrorLoc(SourceLoc loc) { return getSink()->noteInternalErrorLoc(loc); }
CapabilitySet getTargetCaps() { return m_codeGenContext->getTargetCaps(); }
CodeGenContext* getCodeGenContext() { return m_codeGenContext; }
TargetRequest* getTargetReq() { return m_codeGenContext->getTargetReq(); }
Session* getSession() { return m_codeGenContext->getSession(); }
Linkage* getLinkage() { return m_codeGenContext->getLinkage(); }
ComponentType* getProgram() { return m_codeGenContext->getProgram(); }
TargetProgram* getTargetProgram() { return m_codeGenContext->getTargetProgram(); }
//
// Types
//
void ensureTypePrelude(IRType* type);
void emitDeclarator(DeclaratorInfo* declarator) { emitDeclaratorImpl(declarator); }
virtual void emitDeclaratorImpl(DeclaratorInfo* declarator);
void emitType(IRType* type, const StringSliceLoc* nameLoc) { emitTypeImpl(type, nameLoc); }
void emitType(IRType* type, Name* name);
void emitType(IRType* type, String const& name);
void emitType(IRType* type);
void emitType(IRType* type, Name* name, SourceLoc const& nameLoc);
void emitType(IRType* type, NameLoc const& nameAndLoc);
bool hasExplicitConstantBufferOffset(IRInst* cbufferType);
bool isSingleElementConstantBuffer(IRInst* cbufferType);
bool shouldForceUnpackConstantBufferElements(IRInst* cbufferType);
//
// Expressions
//
bool maybeEmitParens(EmitOpInfo& outerPrec, const EmitOpInfo& prec);
void maybeCloseParens(bool needClose);
void emitStringLiteral(const String& value);
void emitVal(IRInst* val, const EmitOpInfo& outerPrec);
void emitStore(IRStore* store);
virtual void _emitStoreImpl(IRStore* store);
void _emitInstAsDefaultInitializedVar(IRInst* inst, IRType* type);
void _emitInstAsVarInitializerImpl(IRInst* inst);
UInt getBindingOffset(EmitVarChain* chain, LayoutResourceKind kind);
UInt getBindingSpace(EmitVarChain* chain, LayoutResourceKind kind);
/// Finds the binding offset for *all* the kinds that match the kindFlags
/// Thus only meaningful if multiple kinds can be treated as the same as far as binding is
/// concerned. In particular is useful for GLSL binding emit, where some HLSL resource kinds can
/// appear but are in effect the same as DescriptorSlot
UInt getBindingOffsetForKinds(EmitVarChain* chain, LayoutResourceKindFlags kindFlags);
UInt getBindingSpaceForKinds(EmitVarChain* chain, LayoutResourceKindFlags kindFlags);
// Utility code for generating unique IDs as needed
// during the emit process (e.g., for declarations
// that didn't originally have names, but now need to).
UInt allocateUniqueID();
// IR-level emit logic
UInt getID(IRInst* value);
/// "Scrub" a name so that it complies with restrictions of the target language.
void appendScrubbedName(const UnownedStringSlice& name, StringBuilder& out);
String generateName(IRInst* inst);
virtual String generateEntryPointNameImpl(IREntryPointDecoration* entryPointDecor);
String getName(IRInst* inst);
String getUnmangledName(IRInst* inst);
void emitSimpleValue(IRInst* inst) { emitSimpleValueImpl(inst); }
virtual bool shouldFoldInstIntoUseSites(IRInst* inst);
void emitOperand(IRInst* inst, EmitOpInfo const& outerPrec)
{
emitOperandImpl(inst, outerPrec);
}
void emitArgs(IRInst* inst);
void emitRateQualifiers(IRInst* value);
void emitRateQualifiersAndAddressSpace(IRInst* value);
void emitInstResultDecl(IRInst* inst);
template<typename T>
IRTargetSpecificDecoration* findBestTargetDecoration(IRInst* inst);
IRTargetIntrinsicDecoration* _findBestTargetIntrinsicDecoration(IRInst* inst);
// Find the definition of a target intrinsic either from __target_intrinsic decoration, or from
// a genericAsm inst in the function body. `outInst` is the decoration or the genericAsm inst.
bool findTargetIntrinsicDefinition(
IRInst* callee,
UnownedStringSlice& outDefinition,
IRInst*& outInst);
// Check if the string being used to define a target intrinsic
// is an "ordinary" name, such that we can simply emit a call
// to the new name with the arguments of the old operation.
static bool isOrdinaryName(const UnownedStringSlice& name);
void emitComInterfaceCallExpr(IRCall* inst, EmitOpInfo const& inOuterPrec);
void emitIntrinsicCallExpr(
IRCall* inst,
UnownedStringSlice intrinsicDefinition,
IRInst* intrinsicInst,
EmitOpInfo const& inOuterPrec);
void emitCallExpr(IRCall* inst, EmitOpInfo outerPrec);
void emitLiveness(IRInst* inst) { emitLivenessImpl(inst); }
void emitInstExpr(IRInst* inst, EmitOpInfo const& inOuterPrec);
void defaultEmitInstExpr(IRInst* inst, EmitOpInfo const& inOuterPrec);
void diagnoseUnhandledInst(IRInst* inst);
void emitInst(IRInst* inst);
void emitSemanticsPrefix(IRInst* inst);
void emitSemantics(IRInst* inst, bool allowOffsets = false);
void emitSemanticsUsingVarLayout(IRVarLayout* varLayout);
void emitDecorationLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling);
void emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling);
/// Emit high-level language statements from a structured region.
void emitRegion(Region* inRegion);
/// Emit high-level language statements from a structured region tree.
void emitRegionTree(RegionTree* regionTree);
// Is an IR function a definition? (otherwise it is a declaration)
bool isDefinition(IRFunc* func);
void emitEntryPointAttributes(IRFunc* irFunc, IREntryPointDecoration* entryPointDecor);
/// Emit high-level statements for the body of a function.
void emitFunctionBody(IRGlobalValueWithCode* code);
void emitFuncHeader(IRFunc* func) { emitFuncHeaderImpl(func); }
void emitSimpleFunc(IRFunc* func) { emitSimpleFuncImpl(func); }
void emitSwitchCaseSelectors(const SwitchRegion::Case* currentCase, bool isDefault)
{
emitSwitchCaseSelectorsImpl(currentCase, isDefault);
}
void emitParamType(IRType* type, String const& name) { emitParamTypeImpl(type, name); }
void emitFuncDecl(IRFunc* func);
void emitFuncDecl(IRFunc* func, const String& name);
IREntryPointLayout* getEntryPointLayout(IRFunc* func);
IREntryPointLayout* asEntryPoint(IRFunc* func);
// Detect if the given IR function/type represents a
// declaration of an intrinsic/builtin for the
// current code-generation target.
bool isTargetIntrinsic(IRInst* func);
void emitFunc(IRFunc* func);
void emitFuncDecorations(IRFunc* func) { emitFuncDecorationsImpl(func); }
void emitStruct(IRStructType* structType);
// This is used independently of `emitStruct` by some GLSL parameter group
// output functionality
void emitStructDeclarationsBlock(IRStructType* structType, bool allowOffsetLayout);
void emitClass(IRClassType* structType);
void emitStructDeclarationSeparator() { emitStructDeclarationSeparatorImpl(); }
virtual void emitStructDeclarationSeparatorImpl();
/// Emit type attributes that should appear after, e.g., a `struct` keyword
void emitPostKeywordTypeAttributes(IRInst* inst) { emitPostKeywordTypeAttributesImpl(inst); }
virtual void emitMemoryQualifiers(IRInst* /*varInst*/){};
virtual void emitStructFieldAttributes(
IRStructType* /* structType */,
IRStructField* /* field */,
bool /* allowOffsetLayout */){};
void emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout);
void emitMeshShaderModifiers(IRInst* varInst);
virtual void emitPackOffsetModifier(
IRInst* /*varInst*/,
IRType* /*valueType*/,
IRPackOffsetDecoration* /*decoration*/
){};
/// Emit modifiers that should apply even for a declaration of an SSA temporary.
virtual void emitTempModifiers(IRInst* temp);
void emitVarModifiers(IRVarLayout* layout, IRInst* varDecl, IRType* varType);
/// Emit the array brackets that go on the end of a declaration of the given type.
void emitArrayBrackets(IRType* inType);
void emitParameterGroup(IRGlobalParam* varDecl, IRUniformParameterGroupType* type);
void emitVar(IRVar* varDecl);
void emitDereferenceOperand(IRInst* inst, EmitOpInfo const& outerPrec);
void emitGlobalVar(IRGlobalVar* varDecl);
void emitGlobalParam(IRGlobalParam* varDecl);
void emitGlobalInst(IRInst* inst);
virtual void emitGlobalInstImpl(IRInst* inst);
void ensureInstOperand(
ComputeEmitActionsContext* ctx,
IRInst* inst,
EmitAction::Level requiredLevel = EmitAction::Level::Definition);
void ensureInstOperandsRec(ComputeEmitActionsContext* ctx, IRInst* inst);
void ensureGlobalInst(
ComputeEmitActionsContext* ctx,
IRInst* inst,
EmitAction::Level requiredLevel);
void emitForwardDeclaration(IRInst* inst);
void computeEmitActions(IRModule* module, List<EmitAction>& ioActions);
void executeEmitActions(List<EmitAction> const& actions);
// Emits front matter, that occurs before the prelude
// Doesn't emit generated function/types that's handled by emitPreModule
void emitFrontMatter(TargetRequest* targetReq) { emitFrontMatterImpl(targetReq); }
void emitPreModule() { emitPreModuleImpl(); }
void emitModule(IRModule* module, DiagnosticSink* sink)
{
m_irModule = module;
emitModuleImpl(module, sink);
}
void emitSimpleType(IRType* type);
void emitVectorTypeName(IRType* elementType, IRIntegerValue elementCount)
{
emitVectorTypeNameImpl(elementType, elementCount);
}
void emitTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName)
{
emitTextureOrTextureSamplerTypeImpl(type, baseName);
}
void emitSubpassInputType(IRSubpassInputType* type) { emitSubpassInputTypeImpl(type); }
virtual RefObject* getExtensionTracker() { return nullptr; }
/// Gets a source language for a target for a target. Returns Unknown if not a known target
static SourceLanguage getSourceLanguage(CodeGenTarget target);
/// Gets the default type name for built in scalar types. Different impls may require something
/// different. Returns an empty slice if not a built in type
static UnownedStringSlice getDefaultBuiltinTypeName(IROp op);
/// Finds the IRNumThreadsDecoration and gets the size from that or sets all
/// dimensions to 1
IRNumThreadsDecoration* getComputeThreadGroupSize(
IRFunc* func,
Int outNumThreads[kThreadGroupAxisCount]);
/// Finds the IRNumThreadsDecoration and gets the size from that or sets all
/// dimensions to 1. If specialization constants are used for an axis, their
/// IDs is reported in non-negative entries of outSpecializationConstantIds.
static IRNumThreadsDecoration* getComputeThreadGroupSize(
IRFunc* func,
Int outNumThreads[kThreadGroupAxisCount],
Int outSpecializationConstantIds[kThreadGroupAxisCount]);
/// Finds the IRWaveSizeDecoration and gets the size from that.
static IRWaveSizeDecoration* getComputeWaveSize(IRFunc* func, Int* outWaveSize);
protected:
virtual void emitGlobalParamDefaultVal(IRGlobalParam* inst) { SLANG_UNUSED(inst); }
virtual void emitPostDeclarationAttributesForType(IRInst* type) { SLANG_UNUSED(type); }
virtual String getTargetBuiltinVarName(IRInst* inst, IRTargetBuiltinVarName builtinName);
virtual bool doesTargetSupportPtrTypes() { return false; }
virtual bool isResourceTypeBindless(IRType* type)
{
SLANG_UNUSED(type);
return false;
}
virtual void emitLayoutSemanticsImpl(
IRInst* inst,
char const* uniformSemanticSpelling,
EmitLayoutSemanticOption layoutSemanticOption)
{
SLANG_UNUSED(inst);
SLANG_UNUSED(uniformSemanticSpelling);
SLANG_UNUSED(layoutSemanticOption);
}
virtual void emitParameterGroupImpl(
IRGlobalParam* varDecl,
IRUniformParameterGroupType* type) = 0;
virtual void emitEntryPointAttributesImpl(
IRFunc* irFunc,
IREntryPointDecoration* entryPointDecor) = 0;
virtual void emitImageFormatModifierImpl(IRInst* varDecl, IRType* varType)
{
SLANG_UNUSED(varDecl);
SLANG_UNUSED(varType);
}
virtual void emitLayoutQualifiersImpl(IRVarLayout* layout) { SLANG_UNUSED(layout); }
/// Emit front matter inserting prelude where appropriate
virtual void emitFrontMatterImpl(TargetRequest* targetReq);
/// Emit any declarations, and other material that is needed before the modules contents
/// For example on targets that don't have built in vector/matrix support, this is where
/// the appropriate generated declarations occur.
virtual void emitPreModuleImpl();
virtual void emitSimpleTypeAndDeclaratorImpl(IRType* type, DeclaratorInfo* declarator);
void emitSimpleTypeAndDeclarator(IRType* type, DeclaratorInfo* declarator)
{
emitSimpleTypeAndDeclaratorImpl(type, declarator);
};
virtual void emitVarKeywordImpl(IRType* type, IRInst* varDecl);
void emitVarKeyword(IRType* type, IRInst* varDecl) { emitVarKeywordImpl(type, varDecl); }
virtual void beforeComputeEmitActions(IRModule* module) { SLANG_UNUSED(module); };
virtual void emitRateQualifiersAndAddressSpaceImpl(IRRate* rate, AddressSpace addressSpace)
{
SLANG_UNUSED(rate);
SLANG_UNUSED(addressSpace);
}
virtual void emitSemanticsPrefixImpl(IRInst* inst) { SLANG_UNUSED(inst); }
virtual void emitSemanticsImpl(IRInst* inst, bool allowOffsetLayout)
{
SLANG_UNUSED(inst);
SLANG_UNUSED(allowOffsetLayout);
}
virtual void emitSimpleFuncParamImpl(IRParam* param);
virtual void emitSimpleFuncParamsImpl(IRFunc* func);
virtual void emitInterpolationModifiersImpl(
IRInst* varInst,
IRType* valueType,
IRVarLayout* layout)
{
SLANG_UNUSED(varInst);
SLANG_UNUSED(valueType);
SLANG_UNUSED(layout);
}
virtual void emitMeshShaderModifiersImpl(IRInst* varInst) { SLANG_UNUSED(varInst) }
virtual void emitSimpleTypeImpl(IRType* type) = 0;
virtual void emitVarDecorationsImpl(IRInst* varDecl) { SLANG_UNUSED(varDecl); }
virtual void emitMatrixLayoutModifiersImpl(IRType* varType) { SLANG_UNUSED(varType); }
virtual void emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc);
virtual void emitSimpleValueImpl(IRInst* inst);
virtual void emitModuleImpl(IRModule* module, DiagnosticSink* sink);
virtual void emitFuncHeaderImpl(IRFunc* func);
virtual void emitSimpleFuncImpl(IRFunc* func);
virtual void emitVarExpr(IRInst* inst, EmitOpInfo const& outerPrec);
virtual void emitOperandImpl(IRInst* inst, EmitOpInfo const& outerPrec);
virtual void emitParamTypeImpl(IRType* type, String const& name);
virtual void emitParamTypeModifier(IRType* type) { SLANG_UNUSED(type); }
virtual void emitIntrinsicCallExprImpl(
IRCall* inst,
UnownedStringSlice intrinsicDefinition,
IRInst* intrinsicInst,
EmitOpInfo const& inOuterPrec);
virtual void emitFunctionPreambleImpl(IRInst* inst) { SLANG_UNUSED(inst); }
virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl)
{
SLANG_UNUSED(decl);
}
virtual void emitIfDecorationsImpl(IRIfElse* ifInst) { SLANG_UNUSED(ifInst); }
virtual void emitSwitchDecorationsImpl(IRSwitch* switchInst) { SLANG_UNUSED(switchInst); }
virtual void emitSwitchCaseSelectorsImpl(const SwitchRegion::Case* currentCase, bool isDefault);
virtual void emitFuncDecorationImpl(IRDecoration* decoration) { SLANG_UNUSED(decoration); }
virtual void emitLivenessImpl(IRInst* inst);
virtual void emitFuncDecorationsImpl(IRFunc* func);
// Only needed for glsl output with $ prefix intrinsics - so perhaps removable in the future
virtual void emitTextureOrTextureSamplerTypeImpl(IRTextureTypeBase* type, char const* baseName)
{
SLANG_UNUSED(type);
SLANG_UNUSED(baseName);
}
bool tryGetIntInfo(IRType* elementType, bool& isSigned, int& bitWidth);
void emitVecNOrScalar(IRVectorType* vectorType, std::function<void()> func);
virtual void emitBitfieldExtractImpl(IRInst* inst);
virtual void emitBitfieldInsertImpl(IRInst* inst);
virtual void emitSubpassInputTypeImpl(IRSubpassInputType* type) { SLANG_UNUSED(type); }
// Again necessary for & prefix intrinsics. May be removable in the future
virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) = 0;
virtual void emitWitnessTable(IRWitnessTable* witnessTable);
void emitComWitnessTable(IRWitnessTable* witnessTable);
virtual void emitInterface(IRInterfaceType* interfaceType);
virtual void emitRTTIObject(IRRTTIObject* rttiObject);
virtual bool tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType)
{
SLANG_UNUSED(varDecl);
SLANG_UNUSED(varType);
return false;
}
virtual bool tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOuterPrec)
{
SLANG_UNUSED(inst);
SLANG_UNUSED(inOuterPrec);
return false;
}
virtual bool tryEmitInstStmtImpl(IRInst* inst)
{
SLANG_UNUSED(inst);
return false;
}
void defaultEmitInstStmt(IRInst* inst);
void emitInstStmt(IRInst* inst);
virtual void emitPostKeywordTypeAttributesImpl(IRInst* inst) { SLANG_UNUSED(inst); }
void _emitFuncTypeDeclaration(IRFuncType* type, IRAttributedType* attributes);
virtual void _emitType(IRType* type, DeclaratorInfo* declarator);
void _emitInst(IRInst* inst);
virtual void _emitPrefixTypeAttr(IRAttr* attr);
virtual void _emitPostfixTypeAttr(IRAttr* attr);
// Emit the argument list (including paranthesis) in a `CallInst`
void _emitCallArgList(IRCall* call, int startingOperandIndex = 1);
virtual void emitCallArg(IRInst* arg);
virtual void emitRequireExtension(IRRequireTargetExtension* inst) { SLANG_UNUSED(inst); }
String _generateUniqueName(const UnownedStringSlice& slice);
// Sort witnessTable entries according to the order defined in the witnessed interface type.
List<IRWitnessTableEntry*> getSortedWitnessTableEntries(IRWitnessTable* witnessTable);
// Special handling for swizzleStore call, save the right-handside vector to a temporary
// variable first, then assign the corresponding elements to the left-handside vector one by
// one.
void _emitSwizzleStorePerElement(IRInst* inst);
String _emitLiteralOneWithType(int bitWidth);
virtual void ensurePrelude(const char* preludeText);
CodeGenContext* m_codeGenContext = nullptr;
IRModule* m_irModule = nullptr;
// The stage for which we are emitting code.
//
// TODO: We should support emitting code that includes multiple
// entry points for different stages, but this value is used
// in some very specific cases to determine how a construct
// should map to GLSL.
//
Stage m_entryPointStage = Stage::Unknown;
// The target language we want to generate code for
CodeGenTarget m_target;
// Source language (based on the more nuanced m_target)
SourceLanguage m_sourceLanguage;
// Where source is written to
SourceWriter* m_writer;
UInt m_uniqueIDCounter = 1;
Dictionary<IRInst*, UInt> m_mapIRValueToID;
HashSet<String> m_irDeclsVisited;
HashSet<String> m_irTupleTypes;
// The "effective" profile that is being used to emit code,
// combining information from the target and entry point.
Profile m_effectiveProfile;
// Map a string name to the number of times we have seen this
// name used so far during code emission.
Dictionary<String, UInt> m_uniqueNameCounters;
// Map an IR instruction to the name that we've decided
// to use for it when emitting code.
Dictionary<IRInst*, String> m_mapInstToName;
OrderedHashSet<IRStringLit*> m_requiredPreludes;
Dictionary<const char*, IRStringLit*> m_builtinPreludes;
// Rename entry point if target doesn't allow the name (e.g., 'main')
virtual String maybeMakeEntryPointNameValid(String name, DiagnosticSink* sink);
// Indicates if we are emiting for DXC cooperative vector POC.
bool isCoopvecPoc = false;
// Indicates if we are emiting for Optix cooperative vector.
bool isOptixCoopVec = false;
// Set of diagnostic IDs that have already been reported to prevent duplicates
HashSet<int> m_reportedDiagnosticIds;
// Set of diagnostic keys (ID + all parameters) that have already been reported to prevent
// duplicates
HashSet<String> m_reportedDiagnosticKeys;
};
} // namespace Slang
#endif
|