-
Notifications
You must be signed in to change notification settings - Fork 285
support specialization constant sized array #6871
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
My thinking is that we should lower such array as a sized array. Why is that not possible?
|
The size of the array should be folded into a The |
It's not impossible. I made this choice is because by lower to unsized array could potentially avoid any potential checks during type checking and IR legalization pass, so that could make this PR simpler, while the two decisions (unsized array vs sized array) should be equally feasible. But maybe I'm overthinking about the cost. |
I don't think there are any checks after IR lowering, and we should be fine there. |
OK, I can change it to sized array, it should be very small change. But the problem still exists, take this example in the description
we want to emit this to something like this:
our currently emit logic won't let me do that. So I guess I will have to implement the logic in emit-spirv. |
Yeah, we will need to find a way to emit this, independent from how we represent this in the type system or IR. |
8bf2a3d
to
9c8ea34
Compare
add one more unit test
9fe0c62
to
7ecbadd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need to make any changes to ir lowering or mangling at all, if we reuse/rename the existing GenericParamIntVal
to point to speicalization constant decls.
We just need to insert the right spirv legalization logic to turn the intermediate expressions (e.g. opAdd etc.) into its own specConst, before it is used in array sizes.
if (elementCount->getType() != getIntType()) | ||
{ | ||
// Canonicalize constant elementCount to int. | ||
if (auto elementCountConstantInt = as<ConstantIntVal>(elementCount)) | ||
{ | ||
elementCount = getIntVal(getIntType(), elementCountConstantInt->getValue()); | ||
} | ||
else if (auto elementCountSpecConstInt = as<SpecializationConstantIntVal>(elementCount)) | ||
{ | ||
elementCount = getSpecConstIntVal(getIntType(), elementCountSpecConstInt->getValue()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this case. The else
branch should handle the specializeation constant case just fine.
@@ -524,6 +529,10 @@ class ASTBuilder : public RefObject | |||
PtrTypeBase* getPtrType(Type* valueType, AddressSpace addrSpace, char const* ptrTypeName); | |||
|
|||
ArrayExpressionType* getArrayType(Type* elementType, IntVal* elementCount); | |||
ArrayExpressionType* getArrayType( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we shouldn't need this.
@@ -386,6 +386,11 @@ class ASTBuilder : public RefObject | |||
return getOrCreate<ConstantIntVal>(type, value); | |||
} | |||
|
|||
SpecializationConstantIntVal* getSpecConstIntVal(Type* type, Val* specConstVal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as we discussed, we just need getDeclRefIntVal
.
else | ||
{ | ||
allConst = false; | ||
} | ||
} | ||
|
||
if (allConst && hasSpecializationConstant) | ||
{ | ||
// If the expression contains a specialization constant, we are not able to constant fold |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't add the hasSpecializationConstant
change here, and just have everything processed the same way as if a specialization constant is a generic value parameter, would anything go wrong?
I feel like things will run just fine if we undo all the changes to this function.
@@ -1974,7 +2006,9 @@ IntVal* SemanticsVisitor::tryConstantFoldDeclRef( | |||
// if they're marked `const`. | |||
if (decl->hasModifier<SpecializationConstantAttribute>() || | |||
decl->hasModifier<VkConstantIdAttribute>()) | |||
return nullptr; | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also need kind == ConstantFoldingKind::SpecializationConstantTime
if (auto specConstElementCount = as<SpecializationConstantIntVal>(elementCount)) | ||
{ | ||
// We need to check if the specialization constant has valid specConst expression | ||
if (!specConstElementCount->getValue()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can we ever run into this case? SpecializationConstantIntVal
either exists and points to a valid var decl, or it doesn't. SpecializationConstantIntVal
should be holding a declref to the var decl.
Val* getValue() | ||
{ | ||
Val* val = getOperand(1); | ||
if (!as<FuncCallIntVal>(val) && !as<DeclRefBase>(val)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SpecializationConstantIntVal
should just be wrapping a declref, val
here shouldn't be a FuncCallIntVal
.
@@ -492,6 +492,8 @@ struct SharedIRGenContext | |||
Dictionary<SourceFile*, IRInst*> mapSourceFileToDebugSourceInst; | |||
Dictionary<String, IRInst*> mapSourcePathToDebugSourceInst; | |||
|
|||
Dictionary<SpecializationConstantIntVal*, IRInst*> mapSpecConstValToIRInst; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need this mapping, if we use the existing GenericParamIntVal
to refer to specialization constants.
@@ -2056,7 +2074,38 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower | |||
auto elementType = lowerType(context, type->getElementType()); | |||
if (!type->isUnsized()) | |||
{ | |||
auto elementCount = lowerSimpleVal(context, type->getElementCount()); | |||
IRInst* elementCount = nullptr; | |||
if (auto specConstIntVal = as<SpecializationConstantIntVal>(type->getElementCount())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't needed. The existing lowering logic for GenericParamIntVal
should just work for specialization constants.
Goal of this PR
We want to support an array whose size can be specialization constant for shared/global variable e.g.
Overview of the solution:
kIROp_SpecializationConstantOpDecoration
.kIROp_SpecializationConstantOpDecoration
.OpSpecConstantOp
, the existing emit logic doesn't support emittingOpSpecConstantOp
, especially this op can embed arithmetic operation at global scope, where we can only emit arithmetic instruct at local. But there are only few instructs we need to support.Overview of the solution:
Note: This PR is not aimed to support all possible opcodes supported by
OpSpecConstantOp
, only those 32-bit integer opcode, because only those types can be used for array size. For those untypical usage, we can leave in the future to extend, current emit struct should be easy to extend.