-
Notifications
You must be signed in to change notification settings - Fork 269
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
Make IRWitnessTable HOISTABLE #6417
base: master
Are you sure you want to change the base?
Make IRWitnessTable HOISTABLE #6417
Conversation
This PR is still work in progress, but any comments and feedback will be welcomed. Currently 17 tests are failing with this PR:
I am investigating what is happening with them. |
/format |
🌈 Formatted, please merge the changes from this PR |
475b891
to
58a5db2
Compare
I pushed more code change.
|
For the remaining problem, here is a minimal repro shader,
When compiled, I get the following error,
It appears that some of IRinst-s are removed by DCE and their uses are replaced by "undefined" incorrectly. |
With my latest changes, the only test failing is
|
/format |
🌈 Formatted, please merge the changes from this PR |
d18a5c7
to
2d863cb
Compare
68be3b0
to
6a8b99d
Compare
/format |
🌈 Formatted, please merge the changes from this PR |
c926457
to
067d554
Compare
/format |
🌈 Formatted, please merge the changes from this PR |
It looks like my PR is failing on a new test,
And Falcor test is also crashing at
|
Changing to draft until I fix the failing test and falcor tests |
It turned out that the test failure of the following test was due to an incorrect resolve of the merge conflict.
|
For the failing Falcor tests, there are two failing tests for "falcor-unit-test":
Both of them looks to have a same assertion failure at
Slang got There are bunch failing tests for "falcor-image-test", but they seem to have a same problem.
|
🌈 Formatted, please merge the changes from this PR |
This commit deduplicates Witnessable by making it HOISTABLE. Three problems were observed when changed to HOISTABLE, and they are addressed in this commit. 1. A HOISTABLE IRInst is immutable once created. `SetOperand()` functions became unavailable. There were code that was modifying WitnessTable after creating it. This commit changed the behavior so that all operands are prepared before creating a new WitnessTable, and all operands are given to its constructor. 1. WitnessTable started to have duplicated decorations and children. Due to the nature of HOISTABLE, when create a new WitnessTable, a pre-existing WitnessTable is returned and reused. There isn't an easy way to tell if the WitnessTable is a brand new or reused at the moment. This commit assumes that it is a brand new only when it has no decorations and chilrend after its creation. 1. In `SimplifyIR()`, the order of children were slightly changed as a result of the optimization. The behavior was little different when WitnessTable became HOISTABLE. This resulted in an error where WitnessTable has a WitnessEntry pointing to an incorrect `IRSpecialize`. In order for it to function properly, `IRSpecialize` had to appear before `IRWitnessTable`.
Fixes the failing test, tests/compute/assoctype-func-param.slang
336254b
to
99b3f50
Compare
/format |
🌈 Formatted, please merge the changes from this PR |
a96b581
to
f768ee7
Compare
This PR is ready for another review. |
// In order to de-duplicate them, Witness-table is marked as Hoistable. | ||
// But it is not exactly a hoistable type and it can be added simpler. | ||
if (inst->getOp() == kIROp_WitnessTable) | ||
addDeduplicatedInst(inst); |
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.
Ah, sorry I wasn’t communicating my meaning clearly earlier. My question was is it sufficient to just call the existing addInst function here, instead of calling the new addDeduplicatedInst?
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.
When I used the exisitng IRBuilder::addInst()
, one of tests was failing. So no, I couldn't use the function.
tests/autodiff/dynamic-dispatch-material.slang
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 I can investigate why it fails if IRBuilder::addInst()
is preferred.
Considering that it is only failing test, I think there might be a problem for the specific use case.
Make
IRWitnessTable
HoistableIntention of the PR
This commit makes
IRWitnessTable
Hoistable so that we can avoid duplicatedIRWitnessTable
.Problems
This commit tries to address the following issues arise after turning
IRWitnessTable
into Hoistable:IRWitnessTable
, instead of a new one.IRWitnessTable
.Implementation
Solution for "1. A Hoistable instance is immutable."
IRWitnessTable::setConcreteType()
is removed, because when anIRInst
is Hoistable, it is treated as immutable. AnyIRInst::setXXX()
methods don't work anymore.There were two places calling
setConcreteType()
and their logic had to change little bit.DeclLoweringVisitor::visitInheritanceDecl()
insource/slang/slang-lower-to-ir.cpp
was callingsetConcreteType()
. It had a little strange logic aroundlowerType()
. TheIRWitnessTable
was added withcontext->setGlobalValue()
first and itsconcreteType
was changed later. This commit works around in a way that it sets the parent ofIRWitnessTable
temporarily and reset it with the correctIRWitnessTable
. Without this logic, it went into an infinite recursion.AutoDiffPass::fillDifferentialTypeImplementation()
insource/slang/slang-ir-autodiff.cpp
was callingsetConcreteType()
. It was changing the concreteType ofinnerResult.diffWitness
. This commit creates a newIRWitnessTable
and copies itsIRWitnessTableEntry
.Solution for "2. When tries to create a duplicated child, you will get a previously created instance of IRWitnessTable, instead of a new one"
After a call to
IRBuilder::createWitnessTable()
, this commit checks if the returnedIRWitnessTable
is a brand new or not. If it is not a new one, we have to avoid adding the decorations and children.This commit decides when to add decorations and children based on whether
IRWitnessTable
has any of decorations or children already. It doesn't seem like a proper way to check. But when I tried, it was difficult to find a bottleneck point where the decorations and children are added toIRWitnessTable
first time. Note that we are not trying to find whenIRWitnessTable
is created for the first time; we need to find if the decorations and children were added once.It might be fine to have duplicated
IRWitnessTableEntry
in most of the cases, but I noticed that it fails an assertion check whenshouldDeepCloneWitnessTable()
returns false incloneWitnessTableImpl()
.Solution for "3. We don't actually want to hoist IRWitnessTable."
The reason why this commit makes
IRWitnessTable
is to prevent the duplicated instances ofIRInst
. But we don't really want to "Hoist" them.When an
IRWitnessTable
gets Hoisted out, it causes unexpected problems and the specialization process fails due to the missingIRWitnessTable
in the input.This commit prevent from hoisting
IRWitnessTable
in_replaceInstUsesWith()
. The way this is implemented feel little hack but we discussed on Slack and decided to go with this. One of the proper approaches could be to add a new flag inIROpFlags
and have a new one likekIROpFlag_Deduplicate
, which is different from justkIROpFlag_Hoistable
.Solution for "4. There can be only one instance of Hoistable and it cannot appear as childs multiple times."
When
IRWitnessTable
is Hoistable, there can be only a unique set of instances. And we cannot have an instance as a duplicated childs. It is becauseIRInst
has only one set ofIRInst* next
andIRInst* prev
.Before this commit, an instance of
IRGeneral
could have duplicated instances ofIRWitnessTable
. As an example,IInteger
interface inherits two other interfaces,IArithmetic
andILogical
. And they both inherits fromIComparable
.When we specialize it in
specializeGenericImpl()
, anIRBlock
gets the following list of children:For the cloning during the specialize, "IRWitnessTable for
IComparable
" must be cloned before the cloning of "IRWitnessTable forIArithmetic
". Because "IRWitnessTable forIArithmetic
" refers "IRWitnessTable forIComparable
" as itsIRWitnessTableEntry
. The order they appear in theIRBlock
as children decides which instances will be cloned first. And "IRWitnessTable forIComparable
" must appear before "IRWitnessTable forIArithmetic
".Note that "IRWitnessTable for
IComparable
" appears twice, The first one was added for "IRWitnessTable forIArithmetic
". And the second one is added for "IRWitnessTable forILogical
".With this commit "IRWitnessTable for
IComparable
" can appear as a child only once inIRBlock
. So it causes an error if it gets the following list:In order to resolve the problem, "IRWitnessTable for
IComparable
" must appear before both "IRWitnessTable forIArithmetic
" and "IRWitnessTable forILogical
" as following:To address the problem, the instances of
IRWitnessTable
is always added to the end of the children list. If it is already added to the list, we don't move. This works out because the AST tree is built based on the dependencies.Solution for "5. Different import/export mangled names were used for the same Witness-table when its type is "enum" interface."
This issue was found while testing with Falcor tests where it uses Conformance-type feature of Slang.
We are using different import and export mangled names for a same Witness-table when the witness-table is for "Enum" interface.
The way we simplify the implementation of "Enum" causes a problem when it comes to generate export/import for the witness-table. And the exact repro step is still unclear.
There were two suggested solutions for the problem and this PR adopted the first option for now. Maybe we want to improve it with the second option later.
option 1, when we produce mangled names for those witness-table, we can use a mangled name with the underlying "int" type instead of the name of the enum type. In this way, all witness-tables for enum types whose underlying type is same will get the same mangled name. It will allow us to deduplicate the witness-table during the linking.
option 2, we can preserve type info for enum type when generating IR. We can still erase all other uses of the type info of enum types for now. But when we generate the witness-table, instead of filling the conforming type operand to IntType, we fill it as EnumType(IntType) where EnumType is a new global IROp code to represent all enum types (like InterfaceType/StructType). This way the operands for the two witness-tables will be different.
"option 1" is more quick and dirty and "option 2" is more proper way to address it.
I should go with "option 1" and improve it with "option 2" approach later.