diff options
| author | Yong He <yonghe@outlook.com> | 2025-10-07 08:53:36 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-07 15:53:36 +0000 |
| commit | 54e1d02715747ee81585bfd23e96a1f4956dbf66 (patch) | |
| tree | 83dfc746883b6b7aee0018bb55d4aea3095400e8 /source/slang/slang-ir-util.cpp | |
| parent | 0dac20642b971191256e058282811cf9307292e7 (diff) | |
Fix a bug that causes a struct field to be initialized twice. (#8619)
We insert field initialization logic at the beginning of every ctor in
`synthesizeCtorBody`, but then immediately inserts another round of
initialization again for explicit ctors in `maybeInsertDefaultInitExpr`,
both called from `SemanticsDeclBodyVisitor::visitAggTypeDecl` right next
to each other.
The fix is to remove `maybeInsertDefaultInitExpr`.
This change also enhances the address aliasing analysis, so that for the
following case:
```
this->member1 = 0;
this->member2 = 0;
this->member1 = param;
```
We can still remove the first assignment to `this->member1` despite
seeing `this->member2=0`, since it is easy to know that `this->member2`
cannot alias with `this->member1`.
Closes #8600.
Diffstat (limited to 'source/slang/slang-ir-util.cpp')
| -rw-r--r-- | source/slang/slang-ir-util.cpp | 65 |
1 files changed, 54 insertions, 11 deletions
diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp index 9bec464dc..5745ef85f 100644 --- a/source/slang/slang-ir-util.cpp +++ b/source/slang/slang-ir-util.cpp @@ -800,6 +800,7 @@ IRInst* getRootAddr(IRInst* addr, List<IRInst*>& outAccessChain, List<IRInst*>* return addr; } + IRInst* getRootBufferOrAddr(IRInst* addr) { auto rootAddr = getRootAddr(addr); @@ -953,11 +954,11 @@ bool canAddressesPotentiallyAlias( if (addr1 == addr2) return true; - addr1 = getRootBufferOrAddr(addr1); - addr2 = getRootBufferOrAddr(addr2); + auto root1 = getRootBufferOrAddr(addr1); + auto root2 = getRootBufferOrAddr(addr2); - auto addr1Class = getAliasingClass(addr1); - auto addr2Class = getAliasingClass(addr2); + auto addr1Class = getAliasingClass(root1); + auto addr2Class = getAliasingClass(root2); if (!canAddrClassesAlias(addr1Class, addr2Class)) return false; @@ -974,17 +975,17 @@ bool canAddressesPotentiallyAlias( case AddressAliasingClass::BoundBuffer: case AddressAliasingClass::BoundTexture: case AddressAliasingClass::ConstantBuffer: - if (addr1 != addr2) + if (root1 != root2) return false; break; } } // A param and a var can never alias. - if (addr1->getOp() == kIROp_Param && addr1->getParent() == func->getFirstBlock() && - addr2->getOp() == kIROp_Var || - addr1->getOp() == kIROp_Var && addr2->getOp() == kIROp_Param && - addr2->getParent() == func->getFirstBlock()) + if (root1->getOp() == kIROp_Param && root1->getParent() == func->getFirstBlock() && + root2->getOp() == kIROp_Var || + root1->getOp() == kIROp_Var && root2->getOp() == kIROp_Param && + root2->getParent() == func->getFirstBlock()) return false; // If one addr is user pointer and one addr is a var, @@ -992,11 +993,53 @@ bool canAddressesPotentiallyAlias( // the var. if (addr1Class == AddressAliasingClass::Var && addr2Class == AddressAliasingClass::UserPointer) { - return canVarAliasWithUserPointer(target, addr1); + return canVarAliasWithUserPointer(target, root1); } if (addr2Class == AddressAliasingClass::Var && addr1Class == AddressAliasingClass::UserPointer) { - return canVarAliasWithUserPointer(target, addr2); + return canVarAliasWithUserPointer(target, root2); + } + + // If two addrs are rooted from the same object but found to statically differ in access chain, + // then they cannot alias. + if (root1 == root2) + { + List<IRInst*> accessChain1; + List<IRInst*> accessChain2; + + // Since getRootBufferOrAddr has a different behavior around + // RWStructuredBufferGetElementPtr compared to getRootAddr, + // we need to call getRootAddr here again to get a simpler access chain + // that we can handle here, so that we don't need to handle the nuance + // of whether or not to trace past any RWStructuredBufferGetElementPtr. + // + root1 = getRootAddr(addr1, accessChain1, nullptr); + root2 = getRootAddr(addr2, accessChain2, nullptr); + if (root1 != root2) + return true; + for (Index i = 0; i < Math::Min(accessChain1.getCount(), accessChain2.getCount()); i++) + { + auto node1 = accessChain1[i]; + auto node2 = accessChain2[i]; + if (as<IRStructKey>(node1) && as<IRStructKey>(node2)) + { + // Two different field keys means the two addresses cannot alias. + // TODO: If we are going to support union types, we need to exclude that + // here. + if (node1 != node2) + return false; + // If the keys are the same, continue looking further down the access chain. + continue; + } + // Two different constant indices means the two addresses cannot alias. + auto index1 = as<IRIntLit>(node1); + auto index2 = as<IRIntLit>(node2); + if (index1 && index2 && index1->getValue() != index2->getValue()) + return false; + // In all other cases, such as when either one of the indices is + // a untime value, we treat the two indices as potentially being the same. + return true; + } } return true; } |
