Skip to content

Commit ce238dd

Browse files
Make sizeof(T) & alignof(T) of generic types work as compile-time constants (#7213)
* Make sizeof(generic) work as compile-time constant * format code --------- Co-authored-by: slangbot <[email protected]>
1 parent 27c6e9b commit ce238dd

File tree

6 files changed

+237
-22
lines changed

6 files changed

+237
-22
lines changed

source/slang/slang-ast-val.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "slang-ast-builder.h"
55
#include "slang-ast-dispatch.h"
6+
#include "slang-ast-natural-layout.h"
67
#include "slang-check-impl.h"
78
#include "slang-diagnostics.h"
89
#include "slang-mangle.h"
@@ -1742,6 +1743,106 @@ Val* FuncCallIntVal::_substituteImplOverride(
17421743
return this;
17431744
}
17441745

1746+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SizeOfIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1747+
1748+
void SizeOfIntVal::_toTextOverride(StringBuilder& out)
1749+
{
1750+
out << "sizeof(";
1751+
getTypeArg()->toText(out);
1752+
out << ")";
1753+
}
1754+
1755+
Val* SizeOfIntVal::tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType)
1756+
{
1757+
ASTNaturalLayoutContext context(astBuilder, nullptr);
1758+
const auto size = context.calcSize(newType);
1759+
1760+
if (!size)
1761+
return nullptr;
1762+
1763+
return astBuilder->getIntVal(intType, size.size);
1764+
}
1765+
1766+
Val* SizeOfIntVal::tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType)
1767+
{
1768+
if (auto result = tryFoldOrNull(astBuilder, intType, newType))
1769+
return result;
1770+
auto result = astBuilder->getOrCreate<SizeOfIntVal>(intType, newType);
1771+
return result;
1772+
}
1773+
1774+
Val* SizeOfIntVal::_substituteImplOverride(
1775+
ASTBuilder* astBuilder,
1776+
SubstitutionSet subst,
1777+
int* ioDiff)
1778+
{
1779+
int diff = 0;
1780+
auto newType = as<Type>(getTypeArg()->substituteImpl(astBuilder, subst, &diff));
1781+
if (!diff)
1782+
return this;
1783+
1784+
(*ioDiff)++;
1785+
return tryFold(astBuilder, getType(), newType);
1786+
}
1787+
1788+
Val* SizeOfIntVal::_resolveImplOverride()
1789+
{
1790+
auto resolvedTypeArg = getTypeArg()->resolve();
1791+
if (resolvedTypeArg == getTypeArg())
1792+
return this;
1793+
return tryFold(getCurrentASTBuilder(), getType(), as<Type>(resolvedTypeArg));
1794+
}
1795+
1796+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AlignOfIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1797+
1798+
void AlignOfIntVal::_toTextOverride(StringBuilder& out)
1799+
{
1800+
out << "alignof(";
1801+
getTypeArg()->toText(out);
1802+
out << ")";
1803+
}
1804+
1805+
Val* AlignOfIntVal::tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType)
1806+
{
1807+
ASTNaturalLayoutContext context(astBuilder, nullptr);
1808+
const auto size = context.calcSize(newType);
1809+
1810+
if (!size)
1811+
return nullptr;
1812+
1813+
return astBuilder->getIntVal(intType, size.alignment);
1814+
}
1815+
1816+
Val* AlignOfIntVal::tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType)
1817+
{
1818+
if (auto result = tryFoldOrNull(astBuilder, intType, newType))
1819+
return result;
1820+
auto result = astBuilder->getOrCreate<AlignOfIntVal>(intType, newType);
1821+
return result;
1822+
}
1823+
1824+
Val* AlignOfIntVal::_substituteImplOverride(
1825+
ASTBuilder* astBuilder,
1826+
SubstitutionSet subst,
1827+
int* ioDiff)
1828+
{
1829+
int diff = 0;
1830+
auto newType = as<Type>(getTypeArg()->substituteImpl(astBuilder, subst, &diff));
1831+
if (!diff)
1832+
return this;
1833+
1834+
(*ioDiff)++;
1835+
return tryFold(astBuilder, getType(), newType);
1836+
}
1837+
1838+
Val* AlignOfIntVal::_resolveImplOverride()
1839+
{
1840+
auto resolvedTypeArg = getTypeArg()->resolve();
1841+
if (resolvedTypeArg == getTypeArg())
1842+
return this;
1843+
return tryFold(getCurrentASTBuilder(), getType(), as<Type>(resolvedTypeArg));
1844+
}
1845+
17451846
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CountOfIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
17461847

17471848
void CountOfIntVal::_toTextOverride(StringBuilder& out)

source/slang/slang-ast-val.h

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,21 +255,65 @@ class FuncCallIntVal : public IntVal
255255
Val* _linkTimeResolveOverride(Dictionary<String, IntVal*>& map);
256256
};
257257

258-
FIDDLE()
259-
class CountOfIntVal : public IntVal
258+
FIDDLE(abstract)
259+
class SizeOfLikeIntVal : public IntVal
260260
{
261261
FIDDLE(...)
262-
CountOfIntVal(Type* inType, Type* typeArg) { setOperands(inType, typeArg); }
262+
SizeOfLikeIntVal(Type* inType, Type* typeArg) { setOperands(inType, typeArg); }
263263

264264
Val* getTypeArg() { return getOperand(1); }
265265

266+
bool _isLinkTimeValOverride() { return false; }
267+
};
268+
269+
FIDDLE()
270+
class SizeOfIntVal : public SizeOfLikeIntVal
271+
{
272+
FIDDLE(...)
273+
SizeOfIntVal(Type* inType, Type* typeArg)
274+
: SizeOfLikeIntVal(inType, typeArg)
275+
{
276+
}
277+
266278
void _toTextOverride(StringBuilder& out);
267279
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
268280
Val* _resolveImplOverride();
269-
bool _isLinkTimeValOverride() { return false; }
270281

271282
static Val* tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType);
283+
static Val* tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType);
284+
};
285+
286+
FIDDLE()
287+
class AlignOfIntVal : public SizeOfLikeIntVal
288+
{
289+
FIDDLE(...)
290+
AlignOfIntVal(Type* inType, Type* typeArg)
291+
: SizeOfLikeIntVal(inType, typeArg)
292+
{
293+
}
272294

295+
void _toTextOverride(StringBuilder& out);
296+
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
297+
Val* _resolveImplOverride();
298+
299+
static Val* tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType);
300+
static Val* tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType);
301+
};
302+
303+
FIDDLE()
304+
class CountOfIntVal : public SizeOfLikeIntVal
305+
{
306+
FIDDLE(...)
307+
CountOfIntVal(Type* inType, Type* typeArg)
308+
: SizeOfLikeIntVal(inType, typeArg)
309+
{
310+
}
311+
312+
void _toTextOverride(StringBuilder& out);
313+
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
314+
Val* _resolveImplOverride();
315+
316+
static Val* tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType);
273317
static Val* tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType);
274318
};
275319

source/slang/slang-check-expr.cpp

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,13 +2060,25 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr(
20602060
}
20612061
}
20622062

2063-
if (auto countOfExpr = expr.as<CountOfExpr>())
2063+
if (auto sizeOfLikeExpr = expr.as<SizeOfLikeExpr>())
20642064
{
2065-
auto type =
2066-
as<Type>(countOfExpr.getExpr()->sizedType->substitute(m_astBuilder, expr.getSubsts()));
2067-
if (type)
2065+
auto type = as<Type>(
2066+
sizeOfLikeExpr.getExpr()->sizedType->substitute(m_astBuilder, expr.getSubsts()));
2067+
2068+
if (auto sizeOfExpr = expr.as<SizeOfExpr>())
2069+
{
2070+
return as<IntVal>(SizeOfIntVal::tryFold(m_astBuilder, expr.getExpr()->type.type, type));
2071+
}
2072+
else if (auto alignOfExpr = expr.as<AlignOfExpr>())
2073+
{
2074+
return as<IntVal>(
2075+
AlignOfIntVal::tryFold(m_astBuilder, expr.getExpr()->type.type, type));
2076+
}
2077+
else if (auto countOfExpr = expr.as<CountOfExpr>())
2078+
{
20682079
return as<IntVal>(
20692080
CountOfIntVal::tryFold(m_astBuilder, expr.getExpr()->type.type, type));
2081+
}
20702082
}
20712083

20722084
// it is possible that we are referring to a generic value param
@@ -2159,20 +2171,6 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr(
21592171
if (val)
21602172
return val;
21612173
}
2162-
else if (auto sizeOfLikeExpr = as<SizeOfLikeExpr>(expr.getExpr()))
2163-
{
2164-
ASTNaturalLayoutContext context(getASTBuilder(), nullptr);
2165-
const auto size = context.calcSize(sizeOfLikeExpr->sizedType);
2166-
if (!size)
2167-
{
2168-
return nullptr;
2169-
}
2170-
2171-
auto value = as<AlignOfExpr>(sizeOfLikeExpr) ? size.alignment : size.size;
2172-
2173-
// We can return as an IntVal
2174-
return getASTBuilder()->getIntVal(expr.getExpr()->type, value);
2175-
}
21762174
else if (auto indexExpr = expr.as<IndexExpr>())
21772175
{
21782176
return tryFoldIndexExpr(indexExpr.getExpr(), kind, circularityInfo);

source/slang/slang-lower-to-ir.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,22 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
16361636
return LoweredValInfo::simple(resultVal);
16371637
}
16381638

1639+
LoweredValInfo visitSizeOfIntVal(SizeOfIntVal* val)
1640+
{
1641+
auto irBuilder = getBuilder();
1642+
auto typeArg = lowerType(context, as<Type>(val->getTypeArg()));
1643+
auto count = irBuilder->emitSizeOf(typeArg);
1644+
return LoweredValInfo::simple(count);
1645+
}
1646+
1647+
LoweredValInfo visitAlignOfIntVal(AlignOfIntVal* val)
1648+
{
1649+
auto irBuilder = getBuilder();
1650+
auto typeArg = lowerType(context, as<Type>(val->getTypeArg()));
1651+
auto count = irBuilder->emitAlignOf(typeArg);
1652+
return LoweredValInfo::simple(count);
1653+
}
1654+
16391655
LoweredValInfo visitCountOfIntVal(CountOfIntVal* val)
16401656
{
16411657
auto irBuilder = getBuilder();

source/slang/slang-mangle.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,21 @@ void emitVal(ManglingContext* context, Val* val)
357357
emitVal(context, lookupIntVal->getWitness());
358358
emitName(context, lookupIntVal->getKey()->getName());
359359
}
360+
else if (auto sizeOfIntVal = dynamicCast<SizeOfIntVal>(val))
361+
{
362+
emitRaw(context, "KSO");
363+
emitVal(context, sizeOfIntVal->getTypeArg());
364+
}
365+
else if (auto alignOfIntVal = dynamicCast<AlignOfIntVal>(val))
366+
{
367+
emitRaw(context, "KAO");
368+
emitVal(context, alignOfIntVal->getTypeArg());
369+
}
370+
else if (auto countOfIntVal = dynamicCast<CountOfIntVal>(val))
371+
{
372+
emitRaw(context, "KCO");
373+
emitVal(context, countOfIntVal->getTypeArg());
374+
}
360375
else if (const auto polynomialIntVal = dynamicCast<PolynomialIntVal>(val))
361376
{
362377
emitRaw(context, "KX");
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -compute -shaderobj
2+
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-slang -compute -shaderobj
3+
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-slang -compute -dx12 -shaderobj
4+
//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compute -shaderobj
5+
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda -compute -shaderobj
6+
7+
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
8+
9+
RWStructuredBuffer<int> outputBuffer;
10+
11+
struct Thing<T>
12+
{
13+
uint8_t data[sizeof(T)];
14+
};
15+
16+
struct AlignThing<T>
17+
{
18+
uint8_t data[alignof(T)];
19+
};
20+
21+
[numthreads(4, 1, 1)]
22+
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
23+
{
24+
const int idx = asint(dispatchThreadID.x);
25+
26+
int size = 0;
27+
28+
switch (idx)
29+
{
30+
case 0: size = sizeof(Thing<float>); break;
31+
case 1: size = sizeof(Thing<float3>); break;
32+
case 2: size = sizeof(AlignThing<float>); break;
33+
case 3: size = sizeof(AlignThing<float3>); break;
34+
}
35+
36+
// CHECK: 4
37+
// CHECK-NEXT: C
38+
// CHECK: 4
39+
// CHECK-NEXT: 4
40+
outputBuffer[idx] = size;
41+
}

0 commit comments

Comments
 (0)