Skip to content

Commit 2503280

Browse files
authored
Dynamic code gen for generic local variables. (shader-slang#1434)
* Dynamic code gen for generic local variables. * Fixes to function calls with generic typed `in` argument. * Fixes per code review comments
1 parent a5a67aa commit 2503280

15 files changed

+582
-56
lines changed

prelude/slang-cpp-prelude.h

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <assert.h>
1919
#include <stdlib.h>
20+
#include <string.h>
2021

2122
#if defined(_MSC_VER)
2223
# define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport)

prelude/slang-cpp-types.h

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
namespace SLANG_PRELUDE_NAMESPACE {
1616
#endif
1717

18+
struct TypeInfo
19+
{
20+
size_t typeSize;
21+
};
22+
1823
template <typename T, size_t SIZE>
1924
struct FixedArray
2025
{

prelude/slang-cuda-prelude.h

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
# define SLANG_CUDA_BOUNDARY_MODE cudaBoundaryModeZero
5555
#endif
5656

57+
struct TypeInfo
58+
{
59+
size_t typeSize;
60+
};
61+
5762
template <typename T, size_t SIZE>
5863
struct FixedArray
5964
{

source/slang/slang-emit-c-like.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,14 @@ void CLikeSourceEmitter::emitInterface(IRInterfaceType* interfaceType)
309309
// This behavior is overloaded by concrete emitters.
310310
}
311311

312+
void CLikeSourceEmitter::emitRTTIObject(IRRTTIObject* rttiObject)
313+
{
314+
SLANG_UNUSED(rttiObject);
315+
// Ignore rtti object by default.
316+
// This is only used in targets that support dynamic dispatching.
317+
}
318+
319+
312320
void CLikeSourceEmitter::emitTypeImpl(IRType* type, const StringSliceLoc* nameAndLoc)
313321
{
314322
if (nameAndLoc)
@@ -908,6 +916,7 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst)
908916
case kIROp_GlobalParam:
909917
case kIROp_Param:
910918
case kIROp_Func:
919+
case kIROp_Alloca:
911920
return false;
912921

913922
// Always fold these in, because they are trivial
@@ -2010,6 +2019,8 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO
20102019
/* Don't need to to output anything for this instruction - it's used for reflecting string literals that
20112020
are hashed with 'getStringHash' */
20122021
break;
2022+
case kIROp_RTTIPointerType:
2023+
break;
20132024

20142025
case kIROp_undefined:
20152026
m_writer->emit(getName(inst));
@@ -3674,6 +3685,10 @@ void CLikeSourceEmitter::emitGlobalInst(IRInst* inst)
36743685
emitWitnessTable(cast<IRWitnessTable>(inst));
36753686
break;
36763687

3688+
case kIROp_RTTIObject:
3689+
emitRTTIObject(cast<IRRTTIObject>(inst));
3690+
break;
3691+
36773692
default:
36783693
// We have an "ordinary" instruction at the global
36793694
// scope, and we should therefore emit it using the

source/slang/slang-emit-c-like.h

+1
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ class CLikeSourceEmitter: public RefObject
334334

335335
virtual void emitWitnessTable(IRWitnessTable* witnessTable);
336336
virtual void emitInterface(IRInterfaceType* interfaceType);
337+
virtual void emitRTTIObject(IRRTTIObject* rttiObject);
337338

338339
virtual void handleCallExprDecorationsImpl(IRInst* funcValue) { SLANG_UNUSED(funcValue); }
339340

source/slang/slang-emit-cpp.cpp

+70-6
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S
394394
{
395395
switch (type->op)
396396
{
397+
case kIROp_OutType:
398+
case kIROp_InOutType:
397399
case kIROp_PtrType:
398400
{
399401
auto ptrType = static_cast<IRPtrType*>(type);
@@ -496,6 +498,7 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S
496498
return SLANG_OK;
497499
}
498500
case kIROp_RawPointerType:
501+
case kIROp_RTTIPointerType:
499502
{
500503
out << "void*";
501504
return SLANG_OK;
@@ -510,6 +513,11 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S
510513
out << "*";
511514
return SLANG_OK;
512515
}
516+
case kIROp_RTTIType:
517+
{
518+
out << "TypeInfo";
519+
return SLANG_OK;
520+
}
513521
default:
514522
{
515523
if (isNominalOp(type->op))
@@ -1692,14 +1700,35 @@ void CPPSourceEmitter::_emitWitnessTableWrappers()
16921700
else
16931701
m_writer->emit(", ");
16941702

1703+
// If the implementation expects a concrete type
1704+
// (either in the form of a pointer for `out`/`inout` parameters,
1705+
// or in the form a a value for `in` parameters, while
1706+
// the interface exposes a raw pointer type (void*),
1707+
// we need to cast the raw pointer type to the appropriate
1708+
// concerete type. (void*->Concrete* / void*->Concrete&).
16951709
if (reqParamType->op == kIROp_RawPointerType &&
1696-
param->getFullType()->op != kIROp_RawPointerType)
1710+
param->getDataType()->op != kIROp_RawPointerType)
16971711
{
1698-
m_writer->emit("*static_cast<");
1699-
emitType(param->getFullType());
1700-
m_writer->emit("*>(");
1701-
m_writer->emit(getName(param));
1702-
m_writer->emit(")");
1712+
if (as<IRPtrTypeBase>(param->getFullType()))
1713+
{
1714+
// The implementation function expects a pointer to the
1715+
// concrete type. This is the case for inout/out parameters.
1716+
m_writer->emit("static_cast<");
1717+
emitType(param->getFullType());
1718+
m_writer->emit(">(");
1719+
m_writer->emit(getName(param));
1720+
m_writer->emit(")");
1721+
}
1722+
else
1723+
{
1724+
// The implementation function expects just a value of the
1725+
// concrete type. We need to insert a dereference in this case.
1726+
m_writer->emit("*static_cast<");
1727+
emitType(param->getFullType());
1728+
m_writer->emit("*>(");
1729+
m_writer->emit(getName(param));
1730+
m_writer->emit(")");
1731+
}
17031732
}
17041733
else
17051734
{
@@ -1773,6 +1802,18 @@ void CPPSourceEmitter::emitInterface(IRInterfaceType* interfaceType)
17731802
m_writer->emit(";\n");
17741803
}
17751804

1805+
void CPPSourceEmitter::emitRTTIObject(IRRTTIObject* rttiObject)
1806+
{
1807+
m_writer->emit("static TypeInfo ");
1808+
m_writer->emit(getName(rttiObject));
1809+
m_writer->emit(" = {");
1810+
auto typeSizeDecoration = rttiObject->findDecoration<IRRTTITypeSizeDecoration>();
1811+
SLANG_ASSERT(typeSizeDecoration);
1812+
m_writer->emit(typeSizeDecoration->getTypeSize());
1813+
m_writer->emit("};\n");
1814+
}
1815+
1816+
17761817
/// Emits witness table type definition given a sorted list of witness tables
17771818
/// acoording to the order defined by `interfaceType`.
17781819
///
@@ -2273,6 +2314,29 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut
22732314
m_writer->emit("))");
22742315
return true;
22752316
}
2317+
case kIROp_RTTIObject:
2318+
{
2319+
m_writer->emit(getName(inst));
2320+
return true;
2321+
}
2322+
case kIROp_Alloca:
2323+
{
2324+
m_writer->emit("alloca(");
2325+
emitOperand(inst->getOperand(0), EmitOpInfo::get(EmitOp::Postfix));
2326+
m_writer->emit("->typeSize)");
2327+
return true;
2328+
}
2329+
case kIROp_Copy:
2330+
{
2331+
m_writer->emit("memcpy(");
2332+
emitOperand(inst->getOperand(0), EmitOpInfo::get(EmitOp::General));
2333+
m_writer->emit(", ");
2334+
emitOperand(inst->getOperand(1), EmitOpInfo::get(EmitOp::General));
2335+
m_writer->emit(", ");
2336+
emitOperand(inst->getOperand(2), EmitOpInfo::get(EmitOp::Postfix));
2337+
m_writer->emit("->typeSize)");
2338+
return true;
2339+
}
22762340
}
22772341
}
22782342

source/slang/slang-emit-cpp.h

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class CPPSourceEmitter: public CLikeSourceEmitter
6767
virtual void emitParamTypeImpl(IRType* type, String const& name) SLANG_OVERRIDE;
6868
virtual void emitWitnessTable(IRWitnessTable* witnessTable) SLANG_OVERRIDE;
6969
virtual void emitInterface(IRInterfaceType* interfaceType) SLANG_OVERRIDE;
70+
virtual void emitRTTIObject(IRRTTIObject* rttiObject) SLANG_OVERRIDE;
7071
virtual bool tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType) SLANG_OVERRIDE;
7172
virtual void emitIntrinsicCallExprImpl(IRCall* inst, IRTargetIntrinsicDecoration* targetIntrinsic, EmitOpInfo const& inOuterPrec) SLANG_OVERRIDE;
7273

source/slang/slang-ir-inst-defs.h

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ INST(Nop, nop, 0, 0)
2626

2727
INST(StringType, String, 0, 0)
2828
INST(RawPointerType, RawPointerType, 0, 0)
29+
INST(RTTIPointerType, RTTIPointerType, 1, 0)
2930

3031
/* ArrayTypeBase */
3132
INST(ArrayType, Array, 2, 0)
@@ -168,6 +169,7 @@ INST(StructType, struct, 0, PARENT)
168169
INST(InterfaceType, interface, 0, 0)
169170
INST(AssociatedType, associated_type, 0, 0)
170171
INST(ThisType, this_type, 0, 0)
172+
INST(RTTIType, rtti_type, 0, 0)
171173

172174
// A TypeType-typed IRValue represents a IRType.
173175
// It is used to represent a type parameter/argument in a generics.
@@ -224,6 +226,8 @@ INST(makeStruct, makeStruct, 0, 0)
224226

225227
INST(Call, call, 1, 0)
226228

229+
INST(RTTIObject, rtti_object, 0, 0)
230+
INST(Alloca, alloca, 1, 0)
227231

228232
INST(WitnessTableEntry, witness_table_entry, 2, 0)
229233
INST(InterfaceRequirementEntry, interface_req_entry, 2, 0)
@@ -234,6 +238,7 @@ INST(Var, var, 0, 0)
234238

235239
INST(Load, load, 1, 0)
236240
INST(Store, store, 2, 0)
241+
INST(Copy, copy, 3, 0)
237242

238243
INST(FieldExtract, get_field, 2, 0)
239244
INST(FieldAddress, get_field_addr, 2, 0)
@@ -527,6 +532,10 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
527532
/* LinkageDecoration */
528533
INST(ImportDecoration, import, 1, 0)
529534
INST(ExportDecoration, export, 1, 0)
535+
536+
/* Decorations for RTTI objects */
537+
INST(RTTITypeSizeDecoration, RTTI_typeSize, 1, 0)
538+
530539
INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration)
531540

532541
INST(SemanticDecoration, semantic, 2, 0)

source/slang/slang-ir-insts.h

+63
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,19 @@ struct IRNameHintDecoration : IRDecoration
143143
}
144144
};
145145

146+
/// A decoration on a RTTIObject providing type size information.
147+
struct IRRTTITypeSizeDecoration : IRDecoration
148+
{
149+
enum { kOp = kIROp_RTTITypeSizeDecoration };
150+
IR_LEAF_ISA(RTTITypeSizeDecoration)
151+
152+
IRIntLit* getTypeSizeOperand() { return cast<IRIntLit>(getOperand(0)); }
153+
IRIntegerValue getTypeSize()
154+
{
155+
return getTypeSizeOperand()->getValue();
156+
}
157+
};
158+
146159
#define IR_SIMPLE_DECORATION(NAME) \
147160
struct IR##NAME : IRDecoration \
148161
{ \
@@ -420,6 +433,26 @@ struct IRLookupWitnessTable : IRInst
420433
IRUse interfaceType;
421434
};
422435

436+
/// Allocates space from local stack.
437+
///
438+
struct IRAlloca : IRInst
439+
{
440+
IR_LEAF_ISA(Alloca)
441+
442+
IRInst* getAllocSize() { return getOperand(0); }
443+
};
444+
445+
/// Copies `size` bytes from `src` to `dst`.
446+
///
447+
struct IRCopy : IRInst
448+
{
449+
IR_LEAF_ISA(Copy)
450+
451+
IRInst* getDst() { return getOperand(0); }
452+
IRInst* getSrc() { return getOperand(1); }
453+
IRInst* getSize() { return getOperand(2); }
454+
};
455+
423456
// Layout decorations
424457

425458
/// A decoration that marks a field key as having been associated
@@ -1122,12 +1155,14 @@ struct IRCall : IRInst
11221155
struct IRLoad : IRInst
11231156
{
11241157
IRUse ptr;
1158+
IR_LEAF_ISA(Load)
11251159
};
11261160

11271161
struct IRStore : IRInst
11281162
{
11291163
IRUse ptr;
11301164
IRUse val;
1165+
IR_LEAF_ISA(Store)
11311166
};
11321167

11331168
struct IRFieldExtract : IRInst
@@ -1137,6 +1172,8 @@ struct IRFieldExtract : IRInst
11371172

11381173
IRInst* getBase() { return base.get(); }
11391174
IRInst* getField() { return field.get(); }
1175+
IR_LEAF_ISA(FieldExtract)
1176+
11401177
};
11411178

11421179
struct IRFieldAddress : IRInst
@@ -1146,6 +1183,8 @@ struct IRFieldAddress : IRInst
11461183

11471184
IRInst* getBase() { return base.get(); }
11481185
IRInst* getField() { return field.get(); }
1186+
IR_LEAF_ISA(FieldAddress)
1187+
11491188
};
11501189

11511190
struct IRGetAddress : IRInst
@@ -1439,6 +1478,16 @@ struct IRWitnessTable : IRInst
14391478
IR_LEAF_ISA(WitnessTable)
14401479
};
14411480

1481+
/// Represents an RTTI object.
1482+
/// An IRRTTIObject has 1 operand, specifying the type
1483+
/// this RTTI object provides info for.
1484+
/// All type info are encapsualted as `IRRTTI*Decoration`s attached
1485+
/// to the object.
1486+
struct IRRTTIObject : IRInst
1487+
{
1488+
IR_LEAF_ISA(RTTIObject)
1489+
};
1490+
14421491
// An instruction that yields an undefined value.
14431492
//
14441493
// Note that we make this an instruction rather than a value,
@@ -1574,6 +1623,8 @@ struct IRBuilder
15741623
IRAssociatedType* getAssociatedType();
15751624
IRThisType* getThisType();
15761625
IRRawPointerType* getRawPointerType();
1626+
IRRTTIPointerType* getRTTIPointerType(IRInst* rttiPtr);
1627+
IRRTTIType* getRTTIType();
15771628

15781629

15791630
IRBasicBlockType* getBasicBlockType();
@@ -1681,6 +1732,10 @@ struct IRBuilder
16811732
IRInst* witnessTableVal,
16821733
IRInst* interfaceMethodVal);
16831734

1735+
IRInst* emitAlloca(IRInst* type, IRInst* rttiObjPtr);
1736+
1737+
IRInst* emitCopy(IRInst* dst, IRInst* src, IRInst* rttiObjPtr);
1738+
16841739
IRInst* emitCallInst(
16851740
IRType* type,
16861741
IRInst* func,
@@ -1712,6 +1767,9 @@ struct IRBuilder
17121767
UInt argCount,
17131768
IRInst* const* args);
17141769

1770+
// Creates an RTTI object. Result is of `IRRTTIType`.
1771+
IRInst* emitMakeRTTIObject(IRInst* typeInst);
1772+
17151773
IRInst* emitMakeVector(
17161774
IRType* type,
17171775
UInt argCount,
@@ -2243,6 +2301,11 @@ struct IRBuilder
22432301
{
22442302
addDecoration(inst, kIROp_FormatDecoration, format);
22452303
}
2304+
2305+
void addRTTITypeSizeDecoration(IRInst* inst, IRIntegerValue value)
2306+
{
2307+
addDecoration(inst, kIROp_RTTITypeSizeDecoration, getIntValue(getIntType(), value));
2308+
}
22462309
};
22472310

22482311
void addHoistableInst(

0 commit comments

Comments
 (0)