From ce238dd878038bf857968931773cc9b10f3b225d Mon Sep 17 00:00:00 2001 From: Julius Ikkala Date: Thu, 22 May 2025 22:10:42 +0300 Subject: 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 <186143334+slangbot@users.noreply.github.com> --- source/slang/slang-ast-val.cpp | 101 +++++++++++++++++++++++++++++++++++++ source/slang/slang-ast-val.h | 52 +++++++++++++++++-- source/slang/slang-check-expr.cpp | 34 ++++++------- source/slang/slang-lower-to-ir.cpp | 16 ++++++ source/slang/slang-mangle.cpp | 15 ++++++ 5 files changed, 196 insertions(+), 22 deletions(-) (limited to 'source') diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp index 1cdca0440..92e170515 100644 --- a/source/slang/slang-ast-val.cpp +++ b/source/slang/slang-ast-val.cpp @@ -3,6 +3,7 @@ #include "slang-ast-builder.h" #include "slang-ast-dispatch.h" +#include "slang-ast-natural-layout.h" #include "slang-check-impl.h" #include "slang-diagnostics.h" #include "slang-mangle.h" @@ -1742,6 +1743,106 @@ Val* FuncCallIntVal::_substituteImplOverride( return this; } +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SizeOfIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +void SizeOfIntVal::_toTextOverride(StringBuilder& out) +{ + out << "sizeof("; + getTypeArg()->toText(out); + out << ")"; +} + +Val* SizeOfIntVal::tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType) +{ + ASTNaturalLayoutContext context(astBuilder, nullptr); + const auto size = context.calcSize(newType); + + if (!size) + return nullptr; + + return astBuilder->getIntVal(intType, size.size); +} + +Val* SizeOfIntVal::tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType) +{ + if (auto result = tryFoldOrNull(astBuilder, intType, newType)) + return result; + auto result = astBuilder->getOrCreate(intType, newType); + return result; +} + +Val* SizeOfIntVal::_substituteImplOverride( + ASTBuilder* astBuilder, + SubstitutionSet subst, + int* ioDiff) +{ + int diff = 0; + auto newType = as(getTypeArg()->substituteImpl(astBuilder, subst, &diff)); + if (!diff) + return this; + + (*ioDiff)++; + return tryFold(astBuilder, getType(), newType); +} + +Val* SizeOfIntVal::_resolveImplOverride() +{ + auto resolvedTypeArg = getTypeArg()->resolve(); + if (resolvedTypeArg == getTypeArg()) + return this; + return tryFold(getCurrentASTBuilder(), getType(), as(resolvedTypeArg)); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AlignOfIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +void AlignOfIntVal::_toTextOverride(StringBuilder& out) +{ + out << "alignof("; + getTypeArg()->toText(out); + out << ")"; +} + +Val* AlignOfIntVal::tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType) +{ + ASTNaturalLayoutContext context(astBuilder, nullptr); + const auto size = context.calcSize(newType); + + if (!size) + return nullptr; + + return astBuilder->getIntVal(intType, size.alignment); +} + +Val* AlignOfIntVal::tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType) +{ + if (auto result = tryFoldOrNull(astBuilder, intType, newType)) + return result; + auto result = astBuilder->getOrCreate(intType, newType); + return result; +} + +Val* AlignOfIntVal::_substituteImplOverride( + ASTBuilder* astBuilder, + SubstitutionSet subst, + int* ioDiff) +{ + int diff = 0; + auto newType = as(getTypeArg()->substituteImpl(astBuilder, subst, &diff)); + if (!diff) + return this; + + (*ioDiff)++; + return tryFold(astBuilder, getType(), newType); +} + +Val* AlignOfIntVal::_resolveImplOverride() +{ + auto resolvedTypeArg = getTypeArg()->resolve(); + if (resolvedTypeArg == getTypeArg()) + return this; + return tryFold(getCurrentASTBuilder(), getType(), as(resolvedTypeArg)); +} + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CountOfIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void CountOfIntVal::_toTextOverride(StringBuilder& out) diff --git a/source/slang/slang-ast-val.h b/source/slang/slang-ast-val.h index 2b4c7ed22..a8b969a94 100644 --- a/source/slang/slang-ast-val.h +++ b/source/slang/slang-ast-val.h @@ -255,21 +255,65 @@ class FuncCallIntVal : public IntVal Val* _linkTimeResolveOverride(Dictionary& map); }; -FIDDLE() -class CountOfIntVal : public IntVal +FIDDLE(abstract) +class SizeOfLikeIntVal : public IntVal { FIDDLE(...) - CountOfIntVal(Type* inType, Type* typeArg) { setOperands(inType, typeArg); } + SizeOfLikeIntVal(Type* inType, Type* typeArg) { setOperands(inType, typeArg); } Val* getTypeArg() { return getOperand(1); } + bool _isLinkTimeValOverride() { return false; } +}; + +FIDDLE() +class SizeOfIntVal : public SizeOfLikeIntVal +{ + FIDDLE(...) + SizeOfIntVal(Type* inType, Type* typeArg) + : SizeOfLikeIntVal(inType, typeArg) + { + } + void _toTextOverride(StringBuilder& out); Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); Val* _resolveImplOverride(); - bool _isLinkTimeValOverride() { return false; } static Val* tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType); + static Val* tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType); +}; + +FIDDLE() +class AlignOfIntVal : public SizeOfLikeIntVal +{ + FIDDLE(...) + AlignOfIntVal(Type* inType, Type* typeArg) + : SizeOfLikeIntVal(inType, typeArg) + { + } + void _toTextOverride(StringBuilder& out); + Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + Val* _resolveImplOverride(); + + static Val* tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType); + static Val* tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType); +}; + +FIDDLE() +class CountOfIntVal : public SizeOfLikeIntVal +{ + FIDDLE(...) + CountOfIntVal(Type* inType, Type* typeArg) + : SizeOfLikeIntVal(inType, typeArg) + { + } + + void _toTextOverride(StringBuilder& out); + Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + Val* _resolveImplOverride(); + + static Val* tryFoldOrNull(ASTBuilder* astBuilder, Type* intType, Type* newType); static Val* tryFold(ASTBuilder* astBuilder, Type* intType, Type* newType); }; diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index ad36a7e4a..db507c060 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -2060,13 +2060,25 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr( } } - if (auto countOfExpr = expr.as()) + if (auto sizeOfLikeExpr = expr.as()) { - auto type = - as(countOfExpr.getExpr()->sizedType->substitute(m_astBuilder, expr.getSubsts())); - if (type) + auto type = as( + sizeOfLikeExpr.getExpr()->sizedType->substitute(m_astBuilder, expr.getSubsts())); + + if (auto sizeOfExpr = expr.as()) + { + return as(SizeOfIntVal::tryFold(m_astBuilder, expr.getExpr()->type.type, type)); + } + else if (auto alignOfExpr = expr.as()) + { + return as( + AlignOfIntVal::tryFold(m_astBuilder, expr.getExpr()->type.type, type)); + } + else if (auto countOfExpr = expr.as()) + { return as( CountOfIntVal::tryFold(m_astBuilder, expr.getExpr()->type.type, type)); + } } // it is possible that we are referring to a generic value param @@ -2159,20 +2171,6 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr( if (val) return val; } - else if (auto sizeOfLikeExpr = as(expr.getExpr())) - { - ASTNaturalLayoutContext context(getASTBuilder(), nullptr); - const auto size = context.calcSize(sizeOfLikeExpr->sizedType); - if (!size) - { - return nullptr; - } - - auto value = as(sizeOfLikeExpr) ? size.alignment : size.size; - - // We can return as an IntVal - return getASTBuilder()->getIntVal(expr.getExpr()->type, value); - } else if (auto indexExpr = expr.as()) { return tryFoldIndexExpr(indexExpr.getExpr(), kind, circularityInfo); diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index f8946f5dc..9920075fe 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -1636,6 +1636,22 @@ struct ValLoweringVisitor : ValVisitor(val->getTypeArg())); + auto count = irBuilder->emitSizeOf(typeArg); + return LoweredValInfo::simple(count); + } + + LoweredValInfo visitAlignOfIntVal(AlignOfIntVal* val) + { + auto irBuilder = getBuilder(); + auto typeArg = lowerType(context, as(val->getTypeArg())); + auto count = irBuilder->emitAlignOf(typeArg); + return LoweredValInfo::simple(count); + } + LoweredValInfo visitCountOfIntVal(CountOfIntVal* val) { auto irBuilder = getBuilder(); diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp index 056c7accb..ea620ebb2 100644 --- a/source/slang/slang-mangle.cpp +++ b/source/slang/slang-mangle.cpp @@ -357,6 +357,21 @@ void emitVal(ManglingContext* context, Val* val) emitVal(context, lookupIntVal->getWitness()); emitName(context, lookupIntVal->getKey()->getName()); } + else if (auto sizeOfIntVal = dynamicCast(val)) + { + emitRaw(context, "KSO"); + emitVal(context, sizeOfIntVal->getTypeArg()); + } + else if (auto alignOfIntVal = dynamicCast(val)) + { + emitRaw(context, "KAO"); + emitVal(context, alignOfIntVal->getTypeArg()); + } + else if (auto countOfIntVal = dynamicCast(val)) + { + emitRaw(context, "KCO"); + emitVal(context, countOfIntVal->getTypeArg()); + } else if (const auto polynomialIntVal = dynamicCast(val)) { emitRaw(context, "KX"); -- cgit v1.2.3