summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-util.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-10-07 08:53:36 -0700
committerGitHub <noreply@github.com>2025-10-07 15:53:36 +0000
commit54e1d02715747ee81585bfd23e96a1f4956dbf66 (patch)
tree83dfc746883b6b7aee0018bb55d4aea3095400e8 /source/slang/slang-ir-util.cpp
parent0dac20642b971191256e058282811cf9307292e7 (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.cpp65
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;
}