summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2020-06-15 13:56:11 -0700
committerGitHub <noreply@github.com>2020-06-15 13:56:11 -0700
commit926e4bb05402eaf4430e52f0fd07c5da79220322 (patch)
treea22d5e46ae911b70452565e4b6ad1f2c0c8c65bf
parent7e7425de730d7b3f4590c71111e22e5103b53200 (diff)
parent3461ed41118480c3494f810cddd3cd8c735e2fbb (diff)
Merge branch 'master' into glsl-loop
-rw-r--r--source/slang/core.meta.slang19
-rw-r--r--source/slang/slang-ir-specialize-resources.cpp34
-rw-r--r--source/slang/slang-lower-to-ir.cpp39
-rw-r--r--tests/diagnostics/void-function-returning-value.slang25
-rw-r--r--tests/diagnostics/void-function-returning-value.slang.expected7
5 files changed, 117 insertions, 7 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 0c39f2c2f..b56ca3085 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -192,7 +192,9 @@ ${{{{
// Declare initializers to convert from various other types
for (int ss = 0; ss < kBaseTypeCount; ++ss)
{
- // Don't allow conversion from `void`
+ // Don't allow conversion to or from `void`
+ if (kBaseTypes[tt].tag == BaseType::Void)
+ continue;
if (kBaseTypes[ss].tag == BaseType::Void)
continue;
@@ -250,6 +252,21 @@ ${{{{
${{{{
break;
}
+
+ // If this is the `void` type, then we want to allow
+ // explicit conversion to it from any other type, using
+ // `(void) someExpression`.
+ //
+ if( kBaseTypes[tt].tag == BaseType::Void )
+ {
+}}}}
+ __generic<T>
+ [__readNone]
+ __init(T value)
+ {}
+${{{{
+ }
+
}}}}
}
diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp
index f72ca6b38..60439abeb 100644
--- a/source/slang/slang-ir-specialize-resources.cpp
+++ b/source/slang/slang-ir-specialize-resources.cpp
@@ -171,6 +171,27 @@ struct ResourceParameterSpecializationContext
return anySpecializableParam;
}
+ // Returns true if `type` is an `IRStructType` with array-typed fields.
+ bool isStructTypeWithArray(IRType* type)
+ {
+ if (auto structType = as<IRStructType>(type))
+ {
+ for (auto field : structType->getFields())
+ {
+ if (auto arrayType = as<IRArrayType>(field->getFieldType()))
+ {
+ return true;
+ }
+ if (auto subStructType = as<IRStructType>(field->getFieldType()))
+ {
+ if (isStructTypeWithArray(subStructType))
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
// Of course, now we need to back-fill the predicates that
// the above function used to evaluate prameters and arguments.
@@ -209,6 +230,8 @@ struct ResourceParameterSpecializationContext
return true;
if(as<IRByteAddressBufferTypeBase>(type))
return true;
+ if (isStructTypeWithArray(type))
+ return true;
}
// For now, we will not treat any other parameters as
@@ -257,7 +280,7 @@ struct ResourceParameterSpecializationContext
// of the indexing operation is also
// suitable for specialization.
//
- if( arg->op == kIROp_getElement )
+ if( arg->op == kIROp_getElement || arg->op == kIROp_Load )
{
auto base = arg->getOperand(0);
@@ -565,6 +588,11 @@ struct ResourceParameterSpecializationContext
//
ioInfo.newArgs.add(oldIndex);
}
+ else if (oldArg->op == kIROp_Load)
+ {
+ auto oldBase = oldArg->getOperand(0);
+ getCallInfoForArg(ioInfo, oldBase);
+ }
else
{
// If we fail to match any of the cases above
@@ -718,6 +746,10 @@ struct ResourceParameterSpecializationContext
return newVal;
}
+ else if (oldArg->op == kIROp_Load)
+ {
+ return getSpecializedValueForArg(ioInfo, oldArg->getOperand(0));
+ }
else
{
// If we don't match one of the above cases,
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 42f53ef22..fa23b3307 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -3610,18 +3610,47 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor>
{
startBlockIfNeeded(stmt);
- // A `return` statement turns into a return
- // instruction. If the statement had an argument
- // expression, then we need to lower that to
- // a value first, and then emit the resulting value.
+ // A `return` statement turns into a `return` instruction,
+ // but we have two kinds of `return`: one for returning
+ // a (non-`void`) value, and one for returning "no value"
+ // (which effectively returns a value of type `void`).
+ //
if( auto expr = stmt->expression )
{
+ // If the AST `return` statement had an expression, then we
+ // need to lower it to the IR at this point, both to
+ // compute its value and (in case we are returning a
+ // `void`-typed expression) to execute its side effects.
+ //
auto loweredExpr = lowerRValueExpr(context, expr);
- getBuilder()->emitReturn(getSimpleVal(context, loweredExpr));
+ // If the AST `return` statement was returning a non-`void`
+ // value, then we need to emit an IR `return` of that value.
+ //
+ if(!expr->type.type->equals(context->astBuilder->getVoidType()))
+ {
+ getBuilder()->emitReturn(getSimpleVal(context, loweredExpr));
+ }
+ else
+ {
+ // If the type of the value returned was `void`, then
+ // we don't want to emit an IR-level `return` with a value,
+ // because that could trip up some of our back-end.
+ //
+ // TODO: We should eventually have only a single IR-level
+ // `return` operation that always takes a value (including
+ // values of type `void`), and then treat an AST `return;`
+ // as equivalent to something like `return void();`.
+ //
+ getBuilder()->emitReturn();
+ }
}
else
{
+ // If we hit this case, then the AST `return` was a `return;`
+ // with no value, which can only occur in a function with
+ // a `void` result type.
+ //
getBuilder()->emitReturn();
}
}
diff --git a/tests/diagnostics/void-function-returning-value.slang b/tests/diagnostics/void-function-returning-value.slang
new file mode 100644
index 000000000..558e37dbc
--- /dev/null
+++ b/tests/diagnostics/void-function-returning-value.slang
@@ -0,0 +1,25 @@
+// void-function-returning-value.slang
+
+// Confirm that we diagnose a `void` function that returns a value.
+
+//DIAGNOSTIC_TEST:SIMPLE:-stage compute -entry main -target dxbc
+
+void good()
+{
+ // Explicit cast to `void` is okay.
+ return (void)1;
+}
+
+void bad()
+{
+ // Implicit cast to `void` is not allowed.
+ return 1;
+}
+
+[numthreads(1, 1, 1)]
+void main(
+ uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ good();
+ bad();
+} \ No newline at end of file
diff --git a/tests/diagnostics/void-function-returning-value.slang.expected b/tests/diagnostics/void-function-returning-value.slang.expected
new file mode 100644
index 000000000..a94132971
--- /dev/null
+++ b/tests/diagnostics/void-function-returning-value.slang.expected
@@ -0,0 +1,7 @@
+result code = -1
+standard error = {
+tests/diagnostics/void-function-returning-value.slang(16): error 30019: expected an expression of type 'void', got 'int'
+tests/diagnostics/void-function-returning-value.slang(16): note: explicit conversion from 'int' to 'void' is possible
+}
+standard output = {
+}