summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-02-13 10:22:54 -0800
committerGitHub <noreply@github.com>2018-02-13 10:22:54 -0800
commit32549707cc9aa67dbc19cbdc0490ffebc8ec253c (patch)
tree4a8d50d9e42d73e045cd6cddf5e5879a43ce7f6b
parent214a1fced7c53b81c00bec67fa2b91a357d5ece4 (diff)
Fix a bug in IR use-def information (#406)
The basic problem here is that when unlinking an `IRUse` from the linked list of uses, there were several cases where I was failing to set the `prevLink` field of the next node to match the `prevLink` field of the node being removed. That doesn't show up when walking the linked list of uses forward, but it breaks it whenever you have subsequent unlinking operations. This change fixes the bugs of that kind I could find, and also adds a debug validation method to try to avoid breaking it again. I also made more access to `IRUse` go through accessor methods rather than using fields directly, to try to avoid this kind of error. I stopped short of making anything `private`, because I tend to find that it creates more hassles than it avoids. A few other fixes along the way: - Made the `List<T>` type default-initialize elements when you resize it. I hadn't realized we weren't doing that. - Add a standalone `dumpIR(IRGlobalValue*)` so help when debugging issues.
-rw-r--r--source/core/list.h6
-rw-r--r--source/slang/emit.cpp18
-rw-r--r--source/slang/ir-insts.h36
-rw-r--r--source/slang/ir-legalize-types.cpp2
-rw-r--r--source/slang/ir-ssa.cpp19
-rw-r--r--source/slang/ir.cpp144
-rw-r--r--source/slang/ir.h23
-rw-r--r--source/slang/syntax.cpp4
-rw-r--r--tests/compute/ssa-reduce-bug.slang34
-rw-r--r--tests/compute/ssa-reduce-bug.slang.expected.txt8
10 files changed, 200 insertions, 94 deletions
diff --git a/source/core/list.h b/source/core/list.h
index 5a94d8b83..68563f20c 100644
--- a/source/core/list.h
+++ b/source/core/list.h
@@ -420,6 +420,12 @@ namespace Slang
{
for (UInt i = 0; i < _count; i++)
newBuffer[i] = static_cast<T&&>(buffer[i]);
+
+ // Default-initialize the remaining elements
+ for(UInt i = _count; i < size; i++)
+ {
+ new(newBuffer + i) T();
+ }
}
FreeBuffer();
}
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 335662ab3..a27492c0b 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -5183,7 +5183,7 @@ emitDeclImpl(decl, nullptr);
for(UInt aa = 0; aa < argCount; ++aa)
{
if(aa != 0) emit(", ");
- emitIROperand(ctx, args[aa].usedValue, mode);
+ emitIROperand(ctx, args[aa].get(), mode);
}
emit(")");
}
@@ -5488,7 +5488,7 @@ emitDeclImpl(decl, nullptr);
for (UInt aa = 0; aa < argCount; ++aa)
{
if (aa != 0) Emit(", ");
- emitIROperand(ctx, args[aa].usedValue, mode);
+ emitIROperand(ctx, args[aa].get(), mode);
}
Emit(")");
return;
@@ -5524,7 +5524,7 @@ emitDeclImpl(decl, nullptr);
UInt argIndex = d - '0';
SLANG_RELEASE_ASSERT((0 <= argIndex) && (argIndex < argCount));
Emit("(");
- emitIROperand(ctx, args[argIndex].usedValue, mode);
+ emitIROperand(ctx, args[argIndex].get(), mode);
Emit(")");
}
break;
@@ -5536,8 +5536,8 @@ emitDeclImpl(decl, nullptr);
// texturing operation.
SLANG_RELEASE_ASSERT(argCount >= 2);
- auto textureArg = args[0].usedValue;
- auto samplerArg = args[1].usedValue;
+ auto textureArg = args[0].get();
+ auto samplerArg = args[1].get();
if (auto baseTextureType = textureArg->type->As<TextureType>())
{
@@ -5576,7 +5576,7 @@ emitDeclImpl(decl, nullptr);
//
// We are going to hack this *hard* for now.
- auto textureArg = args[0].usedValue;
+ auto textureArg = args[0].get();
if (auto baseTextureType = textureArg->type->As<TextureType>())
{
emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler");
@@ -5602,7 +5602,7 @@ emitDeclImpl(decl, nullptr);
// shape.
SLANG_RELEASE_ASSERT(argCount >= 1);
- auto textureArg = args[0].usedValue;
+ auto textureArg = args[0].get();
if (auto baseTextureType = textureArg->type->As<TextureType>())
{
auto elementType = baseTextureType->elementType;
@@ -6269,7 +6269,7 @@ emitDeclImpl(decl, nullptr);
break;
}
- IRValue* arg = args[argIndex].usedValue;
+ IRValue* arg = args[argIndex].get();
emitIROperand(ctx, pp, IREmitMode::Default);
emit(" = ");
@@ -7142,7 +7142,7 @@ emitDeclImpl(decl, nullptr);
if(value->op == kIROp_specialize)
{
- value = ((IRSpecialize*) value)->genericVal.usedValue;
+ value = ((IRSpecialize*) value)->genericVal.get();
}
if(value->op != kIROp_Func)
diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h
index eec42d59a..f53004ae4 100644
--- a/source/slang/ir-insts.h
+++ b/source/slang/ir-insts.h
@@ -124,8 +124,8 @@ struct IRFieldExtract : IRInst
IRUse base;
IRUse field;
- IRValue* getBase() { return base.usedValue; }
- IRValue* getField() { return field.usedValue; }
+ IRValue* getBase() { return base.get(); }
+ IRValue* getField() { return field.get(); }
};
struct IRFieldAddress : IRInst
@@ -133,8 +133,8 @@ struct IRFieldAddress : IRInst
IRUse base;
IRUse field;
- IRValue* getBase() { return base.usedValue; }
- IRValue* getField() { return field.usedValue; }
+ IRValue* getBase() { return base.get(); }
+ IRValue* getField() { return field.get(); }
};
// Terminators
@@ -146,7 +146,7 @@ struct IRReturnVal : IRReturn
{
IRUse val;
- IRValue* getVal() { return val.usedValue; }
+ IRValue* getVal() { return val.get(); }
};
struct IRReturnVoid : IRReturn
@@ -168,7 +168,7 @@ struct IRUnconditionalBranch : IRTerminatorInst
{
IRUse block;
- IRBlock* getTargetBlock() { return (IRBlock*)block.usedValue; }
+ IRBlock* getTargetBlock() { return (IRBlock*)block.get(); }
};
// Special cases of unconditional branch, to handle
@@ -191,8 +191,8 @@ struct IRLoop : IRUnconditionalBranch
// on a `continue`.
IRUse continueBlock;
- IRBlock* getBreakBlock() { return (IRBlock*)breakBlock.usedValue; }
- IRBlock* getContinueBlock() { return (IRBlock*)continueBlock.usedValue; }
+ IRBlock* getBreakBlock() { return (IRBlock*)breakBlock.get(); }
+ IRBlock* getContinueBlock() { return (IRBlock*)continueBlock.get(); }
};
struct IRConditionalBranch : IRTerminatorInst
@@ -201,9 +201,9 @@ struct IRConditionalBranch : IRTerminatorInst
IRUse trueBlock;
IRUse falseBlock;
- IRValue* getCondition() { return condition.usedValue; }
- IRBlock* getTrueBlock() { return (IRBlock*)trueBlock.usedValue; }
- IRBlock* getFalseBlock() { return (IRBlock*)falseBlock.usedValue; }
+ IRValue* getCondition() { return condition.get(); }
+ IRBlock* getTrueBlock() { return (IRBlock*)trueBlock.get(); }
+ IRBlock* getFalseBlock() { return (IRBlock*)falseBlock.get(); }
};
// A conditional branch that represent the test inside a loop
@@ -230,7 +230,7 @@ struct IRIfElse : IRConditionalBranch
{
IRUse afterBlock;
- IRBlock* getAfterBlock() { return (IRBlock*)afterBlock.usedValue; }
+ IRBlock* getAfterBlock() { return (IRBlock*)afterBlock.get(); }
};
// A multi-way branch that represents a source-level `switch`
@@ -240,9 +240,9 @@ struct IRSwitch : IRTerminatorInst
IRUse breakLabel;
IRUse defaultLabel;
- IRValue* getCondition() { return condition.usedValue; }
- IRBlock* getBreakLabel() { return (IRBlock*) breakLabel.usedValue; }
- IRBlock* getDefaultLabel() { return (IRBlock*) defaultLabel.usedValue; }
+ IRValue* getCondition() { return condition.get(); }
+ IRBlock* getBreakLabel() { return (IRBlock*) breakLabel.get(); }
+ IRBlock* getDefaultLabel() { return (IRBlock*) defaultLabel.get(); }
// remaining args are: caseVal, caseLabel, ...
@@ -255,7 +255,7 @@ struct IRSwizzle : IRReturn
{
IRUse base;
- IRValue* getBase() { return base.usedValue; }
+ IRValue* getBase() { return base.get(); }
UInt getElementCount()
{
return getArgCount() - 1;
@@ -271,8 +271,8 @@ struct IRSwizzleSet : IRReturn
IRUse base;
IRUse source;
- IRValue* getBase() { return base.usedValue; }
- IRValue* getSource() { return source.usedValue; }
+ IRValue* getBase() { return base.get(); }
+ IRValue* getSource() { return source.get(); }
UInt getElementCount()
{
return getArgCount() - 2;
diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp
index 4e3bafd31..2e69898e5 100644
--- a/source/slang/ir-legalize-types.cpp
+++ b/source/slang/ir-legalize-types.cpp
@@ -232,7 +232,7 @@ static LegalVal legalizeCall(
return LegalVal::simple(context->builder->emitCallInst(
callInst->type,
- callInst->func.usedValue,
+ callInst->func.get(),
instArgs.Count(),
instArgs.Buffer()));
}
diff --git a/source/slang/ir-ssa.cpp b/source/slang/ir-ssa.cpp
index d58fd22e4..432dfc1b1 100644
--- a/source/slang/ir-ssa.cpp
+++ b/source/slang/ir-ssa.cpp
@@ -110,7 +110,7 @@ bool isPromotableVar(
for (auto u = var->firstUse; u; u = u->nextUse)
{
- auto user = u->user;
+ auto user = u->getUser();
switch (user->op)
{
default:
@@ -231,7 +231,7 @@ IRValue* tryRemoveTrivialPhi(
IRValue* same = nullptr;
for (auto u : phiInfo->operands)
{
- auto usedVal = u.usedValue;
+ auto usedVal = u.get();
assert(usedVal);
if (usedVal == same || usedVal == phi)
@@ -542,8 +542,8 @@ void processBlock(
case kIROp_Store:
{
auto storeInst = (IRStore*)ii;
- auto ptrArg = storeInst->ptr.usedValue;
- auto valArg = storeInst->val.usedValue;
+ auto ptrArg = storeInst->ptr.get();
+ auto valArg = storeInst->val.get();
if (auto var = asPromotableVar(context, ptrArg))
{
@@ -563,7 +563,7 @@ void processBlock(
case kIROp_Load:
{
IRLoad* loadInst = (IRLoad*)ii;
- auto ptrArg = loadInst->ptr.usedValue;
+ auto ptrArg = loadInst->ptr.get();
if (auto var = asPromotableVar(context, ptrArg))
{
@@ -669,10 +669,10 @@ static void breakCriticalEdges(
for (auto edgeUse : criticalEdges)
{
- auto pred = (IRBlock*) edgeUse->user->parent;
+ auto pred = (IRBlock*) edgeUse->getUser()->parent;
assert(pred->op == kIROp_Block);
- auto succ = (IRBlock*)edgeUse->usedValue;
+ auto succ = (IRBlock*)edgeUse->get();
assert(succ->op == kIROp_Block);
IRBuilder builder;
@@ -683,6 +683,8 @@ static void breakCriticalEdges(
// Create a new block that will sit "along" the edge
IRBlock* edgeBlock = builder.createBlock();
+ edgeUse->debugValidate();
+
// The predecessor block should now branch to
// the edge block.
edgeUse->set(edgeBlock);
@@ -709,7 +711,6 @@ void constructSSA(ConstructSSAContext* context)
// because our representation of SSA form doesn't allow for them.
breakCriticalEdges(context);
-
// Figure out what variables we can promote to
// SSA temporaries.
identifyPromotableVars(context);
@@ -766,7 +767,7 @@ void constructSSA(ConstructSSAContext* context)
UInt predIndex = predCounter++;
auto predInfo = *context->blockInfos.TryGetValue(pp);
- IRValue* operandVal = phiInfo->operands[predIndex].usedValue;
+ IRValue* operandVal = phiInfo->operands[predIndex].get();
phiInfo->operands[predIndex].clear();
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index 40c7e20d5..50b0b83e9 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -59,41 +59,81 @@ namespace Slang
//
+ void IRUse::debugValidate()
+ {
+#ifdef _DEBUG
+ auto uv = this->usedValue;
+ if(!uv)
+ {
+ assert(!user);
+ assert(!nextUse);
+ assert(!prevLink);
+ return;
+ }
+
+ auto pp = &uv->firstUse;
+ for(auto u = uv->firstUse; u;)
+ {
+ assert(u->prevLink == pp);
+
+ pp = &u->nextUse;
+ u = u->nextUse;
+ }
+#endif
+ }
+
void IRUse::init(IRUser* u, IRValue* v)
{
+ clear();
+
user = u;
usedValue = v;
-
if(v)
{
nextUse = v->firstUse;
prevLink = &v->firstUse;
+ if(nextUse)
+ {
+ nextUse->prevLink = &this->nextUse;
+ }
+
v->firstUse = this;
}
+
+ debugValidate();
}
- void IRUse::set(IRValue* usedVal)
+ void IRUse::set(IRValue* uv)
{
- // clear out the old value
- if (usedVal)
- {
- if (prevLink)
- *prevLink = nextUse;
- }
-
- init(user, usedVal);
+ init(user, uv);
}
void IRUse::clear()
{
+ // This `IRUse` is part of the linked list
+ // of uses for `usedValue`.
+
+ debugValidate();
+
if (usedValue)
{
+ auto uv = usedValue;
+
*prevLink = nextUse;
- }
+ if(nextUse)
+ {
+ nextUse->prevLink = prevLink;
+ }
+
+ user = nullptr;
+ usedValue = nullptr;
+ nextUse = nullptr;
+ prevLink = nullptr;
- user = nullptr;
- usedValue = nullptr;
+ if(uv->firstUse)
+ uv->firstUse->debugValidate();
+ }
}
//
@@ -250,7 +290,7 @@ namespace Slang
// We will re-use the logic for getting the successor
// list from such an instruction.
- auto successorList = getSuccessors((IRInst*) use->user);
+ auto successorList = getSuccessors((IRInst*) use->getUser());
if(use >= successorList.begin_
&& use < successorList.end_)
@@ -315,7 +355,7 @@ namespace Slang
IRBlock* IRBlock::PredecessorList::Iterator::operator*()
{
if (!use) return nullptr;
- return (IRBlock*)use->user->parent;
+ return (IRBlock*)use->getUser()->parent;
}
IRBlock::SuccessorList IRBlock::getSuccessors()
@@ -351,7 +391,7 @@ namespace Slang
IRBlock* IRBlock::SuccessorList::Iterator::operator*()
{
- return (IRBlock*)use->usedValue;
+ return (IRBlock*)use->get();
}
// IRFunc
@@ -714,7 +754,7 @@ namespace Slang
auto rightArgs = right.inst->getArgs();
for( UInt aa = 0; aa < argCount; ++aa )
{
- if(leftArgs[aa].usedValue != rightArgs[aa].usedValue)
+ if(leftArgs[aa].get() != rightArgs[aa].get())
return false;
}
@@ -731,7 +771,7 @@ namespace Slang
auto args = inst->getArgs();
for( UInt aa = 0; aa < argCount; ++aa )
{
- code = combineHash(code, Slang::GetHashCode(args[aa].usedValue));
+ code = combineHash(code, Slang::GetHashCode(args[aa].get()));
}
return code;
}
@@ -1894,7 +1934,7 @@ namespace Slang
}
else if (auto proxyVal = dynamic_cast<IRProxyVal*>(val))
{
- dumpOperand(context, proxyVal->inst.usedValue);
+ dumpOperand(context, proxyVal->inst.get());
}
else
{
@@ -2283,7 +2323,7 @@ namespace Slang
if (ii != 0)
dump(context, ", ");
- auto argVal = inst->getArgs()[ii].usedValue;
+ auto argVal = inst->getArgs()[ii].get();
dumpOperand(context, argVal);
}
@@ -2449,9 +2489,9 @@ namespace Slang
IRWitnessTableEntry* entry)
{
dump(context, "witness_table_entry(");
- dumpOperand(context, entry->requirementKey.usedValue);
+ dumpOperand(context, entry->requirementKey.get());
dump(context, ",");
- dumpOperand(context, entry->satisfyingVal.usedValue);
+ dumpOperand(context, entry->satisfyingVal.get());
dump(context, ")\n");
}
@@ -2522,6 +2562,20 @@ namespace Slang
dumpIRModule(&context, module);
}
+ void dumpIR(IRGlobalValue* globalVal)
+ {
+ StringBuilder sb;
+
+ IRDumpContext context;
+ context.builder = &sb;
+ context.indent = 0;
+
+ dumpIRGlobalValue(&context, globalVal);
+
+ fprintf(stderr, "%s\n", sb.Buffer());
+ fflush(stderr);
+ }
+
String getSlangIRAssembly(IRModule* module)
{
StringBuilder sb;
@@ -2551,12 +2605,14 @@ namespace Slang
if(!ff)
return;
+ ff->debugValidate();
+
IRUse* uu = ff;
for(;;)
{
// The uses had better all be uses of this
// instruction, or invariants are broken.
- assert(uu->usedValue == this);
+ assert(uu->get() == this);
// Swap this use over to use the other value.
uu->usedValue = other;
@@ -2597,6 +2653,8 @@ namespace Slang
// And `this` will have no uses any more.
this->firstUse = nullptr;
+
+ ff->debugValidate();
}
void IRValue::deallocate()
@@ -2684,15 +2742,7 @@ namespace Slang
for( UInt aa = 0; aa < argCount; ++aa )
{
IRUse& use = getArgs()[aa];
-
- if(!use.usedValue)
- continue;
-
- // Need to unlink this use from the appropriate linked list.
- use.usedValue = nullptr;
- *use.prevLink = use.nextUse;
- use.prevLink = nullptr;
- use.nextUse = nullptr;
+ use.clear();
}
}
@@ -3616,7 +3666,7 @@ namespace Slang
{
auto proxyVal = witness.Value.As<IRProxyVal>();
SLANG_ASSERT(proxyVal);
- return proxyVal->inst.usedValue;
+ return proxyVal->inst.get();
}
}
}
@@ -3651,7 +3701,7 @@ namespace Slang
{
if (auto proxyVal = dynamic_cast<IRProxyVal*>(val))
{
- auto newIRVal = cloneValue(context, proxyVal->inst.usedValue);
+ auto newIRVal = cloneValue(context, proxyVal->inst.get());
RefPtr<IRProxyVal> newProxyVal = new IRProxyVal();
newProxyVal->inst.init(nullptr, newIRVal);
@@ -3879,10 +3929,10 @@ namespace Slang
// Clone the entries in the witness table as well
for( auto originalEntry : originalTable->entries )
{
- auto clonedKey = cloneValue(context, originalEntry->requirementKey.usedValue);
+ auto clonedKey = cloneValue(context, originalEntry->requirementKey.get());
// if a global val with the mangled name already exists, don't clone again
- auto clonedVal = maybeCloneValueWithMangledName(context, (IRGlobalValue*)(originalEntry->satisfyingVal.usedValue));
+ auto clonedVal = maybeCloneValueWithMangledName(context, (IRGlobalValue*)(originalEntry->satisfyingVal.get()));
/*auto clonedEntry = */context->builder->createWitnessTableEntry(
clonedTable,
@@ -4643,7 +4693,7 @@ namespace Slang
// the pointed-to value and not the proxy type-level `Val`
// instead.
- return context->maybeCloneValue(proxyVal->inst.usedValue);
+ return context->maybeCloneValue(proxyVal->inst.get());
}
else
{
@@ -4905,9 +4955,9 @@ namespace Slang
// of involved functions.
for (auto entry : specTable->entries)
{
- if (entry->satisfyingVal.usedValue->op == kIROp_Func)
+ if (entry->satisfyingVal.get()->op == kIROp_Func)
{
- IRFunc* func = (IRFunc*)entry->satisfyingVal.usedValue;
+ IRFunc* func = (IRFunc*)entry->satisfyingVal.get();
auto specFunc = getSpecializedFunc(sharedContext, func, specDeclRef);
entry->satisfyingVal.set(specFunc);
insertGlobalValueSymbol(sharedContext, specFunc);
@@ -5016,7 +5066,7 @@ namespace Slang
{
// We expect the key on the entry to be a decl-ref,
// but lets go ahead and check, just to be sure.
- auto requirementKey = entry->requirementKey.usedValue;
+ auto requirementKey = entry->requirementKey.get();
if(requirementKey->op != kIROp_decl_ref)
continue;
auto keyDeclRef = ((IRDeclRef*) requirementKey)->declRef;
@@ -5039,7 +5089,7 @@ namespace Slang
// If the keys matched, then we use the value from
// this entry.
- auto satisfyingVal = entry->satisfyingVal.usedValue;
+ auto satisfyingVal = entry->satisfyingVal.get();
return satisfyingVal;
}
@@ -5147,11 +5197,11 @@ namespace Slang
// Now we extract the specialized decl-ref that will
// tell us how to specialize things.
- auto specDeclRefVal = (IRDeclRef*)specInst->specDeclRefVal.usedValue;
+ auto specDeclRefVal = (IRDeclRef*)specInst->specDeclRefVal.get();
auto specDeclRef = specDeclRefVal->declRef;
// We need to specialize functions and witness tables
- auto genericVal = specInst->genericVal.usedValue;
+ auto genericVal = specInst->genericVal.get();
if (genericVal->op == kIROp_Func)
{
auto genericFunc = (IRFunc*)genericVal;
@@ -5187,8 +5237,8 @@ namespace Slang
// try find concrete witness table from global scope
IRLookupWitnessTable* lookupInst = (IRLookupWitnessTable*)ii;
IRWitnessTable* witnessTable = nullptr;
- auto srcDeclRef = ((IRDeclRef*)lookupInst->sourceType.usedValue)->declRef;
- auto interfaceDeclRef = ((IRDeclRef*)lookupInst->interfaceType.usedValue)->declRef;
+ auto srcDeclRef = ((IRDeclRef*)lookupInst->sourceType.get())->declRef;
+ auto interfaceDeclRef = ((IRDeclRef*)lookupInst->interfaceType.get())->declRef;
auto mangledName = getMangledNameForConformanceWitness(srcDeclRef, interfaceDeclRef);
witnessTables.TryGetValue(mangledName, witnessTable);
@@ -5221,14 +5271,14 @@ namespace Slang
// We only want to deal with the case where the witness-table
// argument points to a concrete global table.
- auto witnessTableArg = lookupInst->witnessTable.usedValue;
+ auto witnessTableArg = lookupInst->witnessTable.get();
if(witnessTableArg->op != kIROp_witness_table)
continue;
IRWitnessTable* witnessTable = (IRWitnessTable*)witnessTableArg;
// We also need to be sure that the requirement we
// are trying to look up is identified via a decl-ref:
- auto requirementArg = lookupInst->requirementDeclRef.usedValue;
+ auto requirementArg = lookupInst->requirementDeclRef.get();
if(requirementArg->op != kIROp_decl_ref)
continue;
auto requirementDeclRef = ((IRDeclRef*) requirementArg)->declRef;
diff --git a/source/slang/ir.h b/source/slang/ir.h
index 028468308..407506116 100644
--- a/source/slang/ir.h
+++ b/source/slang/ir.h
@@ -82,22 +82,27 @@ IROpInfo getIROpInfo(IROp op);
// A use of another value/inst within an IR operation
struct IRUse
{
+ IRValue* get() { return usedValue; }
+ IRUser* getUser() { return user; }
+
+ void init(IRUser* user, IRValue* usedValue);
+ void set(IRValue* usedValue);
+ void clear();
+
// The value that is being used
- IRValue* usedValue;
+ IRValue* usedValue = nullptr;
// The value that is doing the using.
- IRUser* user;
+ IRUser* user = nullptr;
// The next use of the same value
- IRUse* nextUse;
+ IRUse* nextUse = nullptr;
// A "link" back to where this use is referenced,
// so that we can simplify updates.
- IRUse** prevLink;
+ IRUse** prevLink = nullptr;
- void init(IRUser* user, IRValue* usedValue);
- void set(IRValue* usedValue);
- void clear();
+ void debugValidate();
};
enum IRDecorationOp : uint16_t
@@ -262,7 +267,7 @@ struct IRUser : IRChildValue
IRValue* getArg(UInt index)
{
- return getArgs()[index].usedValue;
+ return getArgs()[index].get();
}
void setArg(UInt index, IRValue* value)
@@ -542,6 +547,8 @@ void printSlangIRAssembly(StringBuilder& builder, IRModule* module);
String getSlangIRAssembly(IRModule* module);
void dumpIR(IRModule* module);
+void dumpIR(IRGlobalValue* globalVal);
+
String dumpIRFunc(IRFunc* func);
}
diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp
index d83a91938..e050fc977 100644
--- a/source/slang/syntax.cpp
+++ b/source/slang/syntax.cpp
@@ -1888,7 +1888,7 @@ void Type::accept(IValVisitor* visitor, void* extra)
if(!otherProxy)
return false;
- return this->inst.usedValue == otherProxy->inst.usedValue;
+ return this->inst.get() == otherProxy->inst.get();
}
String IRProxyVal::ToString()
@@ -1898,7 +1898,7 @@ void Type::accept(IValVisitor* visitor, void* extra)
int IRProxyVal::GetHashCode()
{
- auto hash = Slang::GetHashCode(inst.usedValue);
+ auto hash = Slang::GetHashCode(inst.get());
return hash;
}
diff --git a/tests/compute/ssa-reduce-bug.slang b/tests/compute/ssa-reduce-bug.slang
new file mode 100644
index 000000000..fe53f2ab0
--- /dev/null
+++ b/tests/compute/ssa-reduce-bug.slang
@@ -0,0 +1,34 @@
+// ssa-reduce-bug.slang
+//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
+
+//TEST_INPUT:ubuffer(data=[0 3 1 2 6 4 7 6], stride=4):dxbinding(0),glbinding(0)
+//TEST_INPUT:ubuffer(data=[8 8 8 8 8 8 8 8], stride=4):dxbinding(1),glbinding(1),out
+
+RWStructuredBuffer<int> inputBuffer;
+RWStructuredBuffer<int> outputBuffer;
+
+int2 reduce(int2 val)
+{
+ for(int ii = 0; ii < 4; ++ii)
+ {
+ if(inputBuffer[ii] != 8)
+ {
+ val.x = max(val.x, inputBuffer[ii]);
+ val.y = min(val.y, inputBuffer[ii + 4]);
+ }
+ }
+ return val;
+}
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ uint tid = dispatchThreadID.x;
+
+ int2 inVal = int2(inputBuffer[tid], inputBuffer[tid + 4]);
+
+ int2 outVal = reduce(inVal);
+
+ outputBuffer[tid] = outVal.x;
+ outputBuffer[tid + 4] = outVal.y;
+} \ No newline at end of file
diff --git a/tests/compute/ssa-reduce-bug.slang.expected.txt b/tests/compute/ssa-reduce-bug.slang.expected.txt
new file mode 100644
index 000000000..3c2c99af0
--- /dev/null
+++ b/tests/compute/ssa-reduce-bug.slang.expected.txt
@@ -0,0 +1,8 @@
+3
+3
+3
+3
+4
+4
+4
+4