summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2020-08-07 18:36:01 -0700
committerGitHub <noreply@github.com>2020-08-07 18:36:01 -0700
commitdd980b492aba9ea1540193434184489d9d04608d (patch)
tree2974ad7462bc540729f1685ea6cf31d337f39648
parent20af567033dedea15abb22fb7d344d116d7b99c5 (diff)
AnyValue packing/unpacking pass. (#1480)
* AnyValue packing/unpacking pass. * Add diagnostic for types that does not fit in required AnyValueSize. * Add expected test result * Fix warnings.
-rw-r--r--prelude/slang-cpp-types.h2
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-ir-any-value-marshalling.cpp487
-rw-r--r--source/slang/slang-ir-any-value-marshalling.h14
-rw-r--r--source/slang/slang-ir-insts.h1
-rw-r--r--source/slang/slang-ir-lower-generics.cpp4
-rw-r--r--source/slang/slang-ir.cpp5
-rw-r--r--source/slang/slang.vcxproj4
-rw-r--r--source/slang/slang.vcxproj.filters18
-rw-r--r--tests/diagnostics/interfaces/anyvalue-size-validation.slang29
-rw-r--r--tests/diagnostics/interfaces/anyvalue-size-validation.slang.expected6
11 files changed, 563 insertions, 8 deletions
diff --git a/prelude/slang-cpp-types.h b/prelude/slang-cpp-types.h
index 49461e4f4..69e69f8df 100644
--- a/prelude/slang-cpp-types.h
+++ b/prelude/slang-cpp-types.h
@@ -41,6 +41,7 @@ struct Array
size_t count;
};
+#if 0
template<size_t N>
struct AnyValue
{
@@ -60,6 +61,7 @@ T unpackAnyValue(const AnyValue<N>& val)
memcpy(&result, &val, sizeof(T));
return result;
}
+#endif
/* Constant buffers become a pointer to the contained type, so ConstantBuffer<T> becomes T* in C++ code.
*/
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index ed224c30b..3e0d488f9 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -495,6 +495,7 @@ DIAGNOSTIC(41000, Warning, unreachableCode, "unreachable code detected")
DIAGNOSTIC(41010, Warning, missingReturn, "control flow may reach end of non-'void' function")
+DIAGNOSTIC(41011, Error, typeDoesNotFitAnyValueSize, "type '$0' does not fit in the size required by its conforming interface.")
//
// 5xxxx - Target code generation.
//
diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp
new file mode 100644
index 000000000..26a9fca58
--- /dev/null
+++ b/source/slang/slang-ir-any-value-marshalling.cpp
@@ -0,0 +1,487 @@
+#include "slang-ir-any-value-marshalling.h"
+
+#include "slang-ir-generics-lowering-context.h"
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+
+namespace Slang
+{
+ // This is a subpass of generics lowering IR transformation.
+ // This pass generates packing/unpacking functions for `AnyValue`s,
+ // and replaces all `IRPackAnyValue` and `IRUnpackAnyValue` with calls to these
+ // functions.
+ struct AnyValueMarshallingContext
+ {
+ SharedGenericsLoweringContext* sharedContext;
+
+ // Stores information about generated `AnyValue` struct types.
+ struct AnyValueTypeInfo : RefObject
+ {
+ IRType* type; // The generated IR value for the `AnyValue<N>` struct type.
+ List<IRStructKey*> fieldKeys; // `IRStructKey`s for the fields of the generated type.
+ };
+
+ Dictionary<IRIntegerValue, RefPtr<AnyValueTypeInfo>> generatedAnyValueTypes;
+
+ struct MarshallingFunctionKey
+ {
+ IRType* originalType;
+ IRIntegerValue anyValueSize;
+ bool operator ==(MarshallingFunctionKey other)
+ {
+ return originalType == other.originalType && anyValueSize == other.anyValueSize;
+ }
+ HashCode getHashCode() const
+ {
+ return combineHash(Slang::getHashCode(originalType), Slang::getHashCode(anyValueSize));
+ }
+ };
+
+ struct MarshallingFunctionSet
+ {
+ IRFunc* packFunc;
+ IRFunc* unpackFunc;
+ };
+
+ // Stores the generated packing/unpacking functions for lookup.
+ Dictionary<MarshallingFunctionKey, MarshallingFunctionSet> mapTypeMarshalingFunctions;
+
+ AnyValueTypeInfo* ensureAnyValueType(IRAnyValueType* type)
+ {
+ auto size = getIntVal(type->getSize());
+ if (auto typeInfo = generatedAnyValueTypes.TryGetValue(size))
+ return typeInfo->Ptr();
+ RefPtr<AnyValueTypeInfo> info = new AnyValueTypeInfo();
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ builder.setInsertBefore(type);
+ auto structType = builder.createStructType();
+ info->type = structType;
+ StringBuilder nameSb;
+ nameSb << "AnyValue" << size;
+ builder.addExportDecoration(structType, nameSb.getUnownedSlice());
+ auto fieldCount = (size + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+ for (decltype(fieldCount) i = 0; i < fieldCount; i++)
+ {
+ auto key = builder.createStructKey();
+ nameSb.Clear();
+ nameSb << "field" << i;
+ builder.addNameHintDecoration(key, nameSb.getUnownedSlice());
+ nameSb << "_anyVal" << size;
+ builder.addExportDecoration(key, nameSb.getUnownedSlice());
+ builder.createStructField(structType, key, builder.getUIntType());
+ info->fieldKeys.add(key);
+ }
+ generatedAnyValueTypes[size] = info;
+ return info.Ptr();
+ }
+
+ struct TypeMarshallingContext
+ {
+ AnyValueTypeInfo* anyValInfo;
+ uint32_t fieldOffset;
+ uint32_t intraFieldOffset;
+ IRType* uintPtrType;
+ IRInst* anyValueVar;
+ // Defines what to do with basic typed data elements.
+ virtual void marshalBasicType(IRBuilder* builder, IRType* dataType, IRInst* concreteTypedVar) = 0;
+
+ // Validates that the type fits in the given AnyValueSize.
+ // After calling emitMarshallingCode, `fieldOffset` will be increased to the required `AnyValue` size.
+ // If this is larger than the provided AnyValue size, report a dianogstic. We might want to front load
+ // this in a separate IR validation pass in the future, but this is the easiest way to report the
+ // diagnostic now.
+ void validateAnyTypeSize(DiagnosticSink* sink, IRType* concreteType)
+ {
+ if (fieldOffset > static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
+ {
+ sink->diagnose(concreteType->sourceLoc, Diagnostics::typeDoesNotFitAnyValueSize, concreteType);
+ }
+ }
+ };
+
+ void emitMarshallingCode(
+ IRBuilder* builder,
+ TypeMarshallingContext* context,
+ IRInst* concreteTypedVar)
+ {
+ auto dataType = cast<IRPtrTypeBase>(concreteTypedVar->getDataType())->getValueType();
+ switch (dataType->op)
+ {
+ case kIROp_IntType:
+ case kIROp_FloatType:
+ case kIROp_UIntType:
+ case kIROp_UInt64Type:
+ case kIROp_Int64Type:
+ case kIROp_DoubleType:
+ case kIROp_Int8Type:
+ case kIROp_Int16Type:
+ case kIROp_UInt8Type:
+ case kIROp_UInt16Type:
+ case kIROp_HalfType:
+ context->marshalBasicType(builder, dataType, concreteTypedVar);
+ break;
+ case kIROp_VectorType:
+ {
+ auto vectorType = static_cast<IRVectorType*>(dataType);
+ auto elementType = vectorType->getElementType();
+ auto elementCount = getIntVal(vectorType->getElementCount());
+ for (IRIntegerValue i = 0; i < elementCount; i++)
+ {
+ auto elementVal = builder->emitElementExtract(
+ elementType,
+ concreteTypedVar,
+ builder->getIntValue(builder->getIntType(), i));
+ emitMarshallingCode(builder, context, elementVal);
+ }
+ break;
+ }
+ case kIROp_MatrixType:
+ {
+ auto matrixType = static_cast<IRMatrixType*>(dataType);
+ auto elementType = matrixType->getElementType();
+ auto colCount = getIntVal(matrixType->getColumnCount());
+ auto rowCount = getIntVal(matrixType->getRowCount());
+ for (IRIntegerValue i = 0; i < colCount; i++)
+ {
+ auto col = builder->emitElementAddress(
+ elementType,
+ concreteTypedVar,
+ builder->getIntValue(builder->getIntType(), i));
+ for (IRIntegerValue j = 0; j < rowCount; j++)
+ {
+ auto element = builder->emitElementExtract(
+ elementType,
+ col,
+ builder->getIntValue(builder->getIntType(), i));
+ emitMarshallingCode(builder, context, element);
+ }
+ }
+ break;
+ }
+ case kIROp_StructType:
+ {
+ auto structType = cast<IRStructType>(dataType);
+ for (auto field : structType->getFields())
+ {
+ auto fieldAddr = builder->emitFieldAddress(
+ builder->getPtrType(field->getFieldType()),
+ concreteTypedVar,
+ field->getKey());
+ emitMarshallingCode(builder, context, fieldAddr);
+ }
+ break;
+ }
+ case kIROp_ArrayType:
+ {
+ auto arrayType = cast<IRArrayType>(dataType);
+ auto elementPtrType = builder->getPtrType(arrayType->getElementType());
+ for (IRIntegerValue i = 0; i < getIntVal(arrayType->getElementCount()); i++)
+ {
+ auto fieldAddr = builder->emitElementAddress(
+ elementPtrType,
+ concreteTypedVar,
+ builder->getIntValue(builder->getIntType(), i));
+ emitMarshallingCode(builder, context, fieldAddr);
+ }
+ break;
+ }
+ default:
+ SLANG_UNIMPLEMENTED_X("Unimplemented type packing");
+ break;
+ }
+ }
+
+ struct TypePackingContext : TypeMarshallingContext
+ {
+ virtual void marshalBasicType(IRBuilder* builder, IRType* dataType, IRInst* concreteVar) override
+ {
+ switch (dataType->op)
+ {
+ case kIROp_IntType:
+ case kIROp_FloatType:
+ {
+ if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
+ {
+ auto srcVal = builder->emitLoad(concreteVar);
+ auto dstVal = builder->emitBitCast(builder->getUIntType(), srcVal);
+ auto dstAddr = builder->emitFieldAddress(
+ uintPtrType,
+ anyValueVar,
+ anyValInfo->fieldKeys[fieldOffset]);
+ builder->emitStore(dstAddr, dstVal);
+ }
+ fieldOffset++;
+ break;
+ }
+ case kIROp_UIntType:
+ {
+ if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
+ {
+ auto srcVal = builder->emitLoad(concreteVar);
+ auto dstAddr = builder->emitFieldAddress(
+ uintPtrType,
+ anyValueVar,
+ anyValInfo->fieldKeys[fieldOffset]);
+ builder->emitStore(dstAddr, srcVal);
+ }
+ fieldOffset++;
+ break;
+ }
+ case kIROp_UInt64Type:
+ case kIROp_Int64Type:
+ case kIROp_DoubleType:
+ case kIROp_Int8Type:
+ case kIROp_Int16Type:
+ case kIROp_UInt8Type:
+ case kIROp_UInt16Type:
+ case kIROp_HalfType:
+ SLANG_UNIMPLEMENTED_X("AnyValue type packing for non 32-bit elements");
+ break;
+ default:
+ SLANG_UNREACHABLE("unknown basic type");
+ }
+ }
+ };
+
+ IRFunc* generatePackingFunc(IRType* type, IRAnyValueType* anyValueType)
+ {
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ builder.setInsertBefore(type);
+ auto anyValInfo = ensureAnyValueType(anyValueType);
+
+ auto func = builder.createFunc();
+
+ StringBuilder nameSb;
+ nameSb << "packAnyValue" << getIntVal(anyValueType->getSize());
+ builder.addNameHintDecoration(func, nameSb.getUnownedSlice());
+ // Currently we don't add linkage to the generated func, since we
+ // do not have a way to compute mangled names from an IR entity.
+ // This will leads to duplicate packing functions in linked code
+ // but there won't be correctness issues.
+
+ auto funcType = builder.getFuncType(1, &type, anyValInfo->type);
+ func->setFullType(funcType);
+ builder.setInsertInto(func);
+
+ builder.emitBlock();
+
+ auto param = builder.emitParam(type);
+ auto concreteTypedVar = builder.emitVar(type);
+ builder.emitStore(concreteTypedVar, param);
+ auto resultVar = builder.emitVar(anyValInfo->type);
+
+ TypePackingContext context;
+ context.anyValInfo = anyValInfo;
+ context.fieldOffset = context.intraFieldOffset = 0;
+ context.uintPtrType = builder.getPtrType(builder.getUIntType());
+ context.anyValueVar = resultVar;
+ emitMarshallingCode(&builder, &context, concreteTypedVar);
+ context.validateAnyTypeSize(sharedContext->sink, type);
+ auto load = builder.emitLoad(resultVar);
+ builder.emitReturn(load);
+ return func;
+ }
+
+ struct TypeUnpackingContext : TypeMarshallingContext
+ {
+ virtual void marshalBasicType(IRBuilder* builder, IRType* dataType, IRInst* concreteVar) override
+ {
+ switch (dataType->op)
+ {
+ case kIROp_IntType:
+ case kIROp_FloatType:
+ {
+ if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
+ {
+ auto srcAddr = builder->emitFieldAddress(
+ uintPtrType,
+ anyValueVar,
+ anyValInfo->fieldKeys[fieldOffset]);
+ auto srcVal = builder->emitLoad(srcAddr);
+ srcVal = builder->emitBitCast(dataType, srcVal);
+ builder->emitStore(concreteVar, srcVal);
+ }
+ fieldOffset++;
+ break;
+ }
+ case kIROp_UIntType:
+ {
+ if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
+ {
+ auto srcAddr = builder->emitFieldAddress(
+ uintPtrType,
+ anyValueVar,
+ anyValInfo->fieldKeys[fieldOffset]);
+ auto srcVal = builder->emitLoad(srcAddr);
+ builder->emitStore(concreteVar, srcVal);
+ }
+ fieldOffset++;
+ break;
+ }
+ case kIROp_UInt64Type:
+ case kIROp_Int64Type:
+ case kIROp_DoubleType:
+ case kIROp_Int8Type:
+ case kIROp_Int16Type:
+ case kIROp_UInt8Type:
+ case kIROp_UInt16Type:
+ case kIROp_HalfType:
+ SLANG_UNIMPLEMENTED_X("AnyValue type packing for non 32-bit elements");
+ break;
+ default:
+ SLANG_UNREACHABLE("unknown basic type");
+ }
+ }
+ };
+
+ IRFunc* generateUnpackingFunc(IRType* type, IRAnyValueType* anyValueType)
+ {
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ builder.setInsertBefore(type);
+ auto anyValInfo = ensureAnyValueType(anyValueType);
+
+ auto func = builder.createFunc();
+
+ StringBuilder nameSb;
+ nameSb << "unpackAnyValue" << getIntVal(anyValueType->getSize());
+ builder.addNameHintDecoration(func, nameSb.getUnownedSlice());
+
+ auto funcType = builder.getFuncType(1, &anyValInfo->type, type);
+ func->setFullType(funcType);
+ builder.setInsertInto(func);
+
+ builder.emitBlock();
+
+ auto param = builder.emitParam(anyValInfo->type);
+ auto anyValueVar = builder.emitVar(anyValInfo->type);
+ builder.emitStore(anyValueVar, param);
+ auto resultVar = builder.emitVar(type);
+
+ TypeUnpackingContext context;
+ context.anyValInfo = anyValInfo;
+ context.fieldOffset = context.intraFieldOffset = 0;
+ context.uintPtrType = builder.getPtrType(builder.getUIntType());
+ context.anyValueVar = anyValueVar;
+ emitMarshallingCode(&builder, &context, resultVar);
+ auto load = builder.emitLoad(resultVar);
+ builder.emitReturn(load);
+ return func;
+ }
+
+ // Ensures the marshalling functions between `type` and `anyValueType` are already generated.
+ // Returns the generated marshalling functions.
+ MarshallingFunctionSet ensureMarshallingFunc(IRType* type, IRAnyValueType* anyValueType)
+ {
+ auto size = getIntVal(anyValueType->getSize());
+ MarshallingFunctionKey key;
+ key.originalType = type;
+ key.anyValueSize = size;
+ MarshallingFunctionSet funcSet;
+ if (mapTypeMarshalingFunctions.TryGetValue(key, funcSet))
+ return funcSet;
+ funcSet.packFunc = generatePackingFunc(type, anyValueType);
+ funcSet.unpackFunc = generateUnpackingFunc(type, anyValueType);
+ mapTypeMarshalingFunctions[key] = funcSet;
+ return funcSet;
+ }
+
+ void processPackInst(IRPackAnyValue* packInst)
+ {
+ auto operand = packInst->getValue();
+ auto func = ensureMarshallingFunc(
+ operand->getDataType(),
+ cast<IRAnyValueType>(packInst->getDataType()));
+ IRBuilder builderStorage;
+ auto builder = &builderStorage;
+ builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
+ builder->setInsertBefore(packInst);
+ auto callInst = builder->emitCallInst(packInst->getDataType(), func.packFunc, 1, &operand);
+ packInst->replaceUsesWith(callInst);
+ packInst->removeAndDeallocate();
+ }
+
+ void processUnpackInst(IRUnpackAnyValue* unpackInst)
+ {
+ auto operand = unpackInst->getValue();
+ auto func = ensureMarshallingFunc(
+ unpackInst->getDataType(),
+ cast<IRAnyValueType>(operand->getDataType()));
+ IRBuilder builderStorage;
+ auto builder = &builderStorage;
+ builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
+ builder->setInsertBefore(unpackInst);
+ auto callInst = builder->emitCallInst(unpackInst->getDataType(), func.unpackFunc, 1, &operand);
+ unpackInst->replaceUsesWith(callInst);
+ unpackInst->removeAndDeallocate();
+ }
+
+ void processAnyValueType(IRAnyValueType* type)
+ {
+ auto info = ensureAnyValueType(type);
+ type->replaceUsesWith(info->type);
+ }
+
+ void processInst(IRInst* inst)
+ {
+ if (auto packInst = as<IRPackAnyValue>(inst))
+ {
+ processPackInst(packInst);
+ }
+ else if (auto unpackInst = as<IRUnpackAnyValue>(inst))
+ {
+ processUnpackInst(unpackInst);
+ }
+ }
+
+ void processModule()
+ {
+ // We start by initializing our shared IR building state,
+ // since we will re-use that state for any code we
+ // generate along the way.
+ //
+ SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
+ sharedBuilder->module = sharedContext->module;
+ sharedBuilder->session = sharedContext->module->session;
+
+ sharedContext->addToWorkList(sharedContext->module->getModuleInst());
+
+ // Process all instructions and translate all `IRPackAnyValue` and `IRUnpackAnyValue`.
+ while (sharedContext->workList.getCount() != 0)
+ {
+ // We will then iterate until our work list goes dry.
+ //
+ while (sharedContext->workList.getCount() != 0)
+ {
+ IRInst* inst = sharedContext->workList.getLast();
+
+ sharedContext->workList.removeLast();
+ sharedContext->workListSet.Remove(inst);
+
+ processInst(inst);
+
+ for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
+ {
+ sharedContext->addToWorkList(child);
+ }
+ }
+ }
+
+ // Finally, replace all `AnyValueType` with the actual struct type that implements it.
+ for (auto inst : sharedContext->module->getModuleInst()->getChildren())
+ {
+ if (auto anyValueType = as<IRAnyValueType>(inst))
+ processAnyValueType(anyValueType);
+ }
+ }
+ };
+
+ void generateAnyValueMarshallingFunctions(SharedGenericsLoweringContext* sharedContext)
+ {
+ AnyValueMarshallingContext context;
+ context.sharedContext = sharedContext;
+ context.processModule();
+ }
+}
diff --git a/source/slang/slang-ir-any-value-marshalling.h b/source/slang/slang-ir-any-value-marshalling.h
new file mode 100644
index 000000000..943b61aa3
--- /dev/null
+++ b/source/slang/slang-ir-any-value-marshalling.h
@@ -0,0 +1,14 @@
+// slang-ir-any-value-marshalling.h
+#pragma once
+
+namespace Slang
+{
+ struct SharedGenericsLoweringContext;
+
+ /// Generates functions that pack and unpack `AnyValue`s, and replaces
+ /// all `IRPackAnyValue` and `IRUnpackAnyValue` instructions with calls
+ /// to these packing/unpacking functions.
+ /// This is a sub-pass of lower-generics.
+ void generateAnyValueMarshallingFunctions(
+ SharedGenericsLoweringContext* sharedContext);
+}
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index cd2babfa6..e022b353c 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -1693,6 +1693,7 @@ struct IRBuilder
IRBasicType* getVoidType();
IRBasicType* getBoolType();
IRBasicType* getIntType();
+ IRBasicType* getUIntType();
IRStringType* getStringType();
IRAssociatedType* getAssociatedType(ArrayView<IRInterfaceType*> constraintTypes);
IRThisType* getThisType(IRInterfaceType* interfaceType);
diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp
index 9960b7451..7df590b23 100644
--- a/source/slang/slang-ir-lower-generics.cpp
+++ b/source/slang/slang-ir-lower-generics.cpp
@@ -1,6 +1,7 @@
// slang-ir-lower-generics.cpp
#include "slang-ir-lower-generics.h"
+#include "slang-ir-any-value-marshalling.h"
#include "slang-ir-generics-lowering-context.h"
#include "slang-ir-lower-generic-function.h"
#include "slang-ir-lower-generic-call.h"
@@ -22,10 +23,11 @@ namespace Slang
lowerGenericFunctions(&sharedContext);
lowerGenericType(&sharedContext);
lowerGenericCalls(&sharedContext);
+ generateWitnessTableWrapperFunctions(&sharedContext);
+ generateAnyValueMarshallingFunctions(&sharedContext);
// We might have generated new temporary variables during lowering.
// An SSA pass can clean up unnecessary load/stores.
constructSSA(module);
eliminateDeadCode(module);
- generateWitnessTableWrapperFunctions(&sharedContext);
}
} // namespace Slang
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 2c9aee817..1a6187a92 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -2222,6 +2222,11 @@ namespace Slang
return (IRBasicType*)getType(kIROp_IntType);
}
+ IRBasicType* IRBuilder::getUIntType()
+ {
+ return (IRBasicType*)getType(kIROp_UIntType);
+ }
+
IRStringType* IRBuilder::getStringType()
{
return (IRStringType*)getType(kIROp_StringType);
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 8df498a11..97f4bba25 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -221,6 +221,7 @@
<ClInclude Include="slang-glsl-extension-tracker.h" />
<ClInclude Include="slang-hlsl-intrinsic-set.h" />
<ClInclude Include="slang-image-format-defs.h" />
+ <ClInclude Include="slang-ir-any-value-marshalling.h" />
<ClInclude Include="slang-ir-bind-existentials.h" />
<ClInclude Include="slang-ir-byte-address-legalize.h" />
<ClInclude Include="slang-ir-clone.h" />
@@ -323,6 +324,7 @@
<ClCompile Include="slang-file-system.cpp" />
<ClCompile Include="slang-glsl-extension-tracker.cpp" />
<ClCompile Include="slang-hlsl-intrinsic-set.cpp" />
+ <ClCompile Include="slang-ir-any-value-marshalling.cpp" />
<ClCompile Include="slang-ir-bind-existentials.cpp" />
<ClCompile Include="slang-ir-byte-address-legalize.cpp" />
<ClCompile Include="slang-ir-clone.cpp" />
@@ -404,4 +406,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project> \ No newline at end of file
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index 6e0a4b80b..679e773d0 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -114,6 +114,9 @@
<ClInclude Include="slang-image-format-defs.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="slang-ir-any-value-marshalling.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="slang-ir-bind-existentials.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -177,6 +180,9 @@
<ClInclude Include="slang-ir-lower-generic-function.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="slang-ir-lower-generic-type.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="slang-ir-lower-generics.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -309,9 +315,6 @@
<ClInclude Include="slang-visitor.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="slang-ir-lower-generic-type.h">
- <Filter>Header Files</Filter>
- </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="slang-ast-builder.cpp">
@@ -416,6 +419,9 @@
<ClCompile Include="slang-hlsl-intrinsic-set.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="slang-ir-any-value-marshalling.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-ir-bind-existentials.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -476,6 +482,9 @@
<ClCompile Include="slang-ir-lower-generic-function.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="slang-ir-lower-generic-type.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-ir-lower-generics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -605,9 +614,6 @@
<ClCompile Include="slang.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="slang-ir-lower-generic-type.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="core.meta.slang">
diff --git a/tests/diagnostics/interfaces/anyvalue-size-validation.slang b/tests/diagnostics/interfaces/anyvalue-size-validation.slang
new file mode 100644
index 000000000..b7cd5ba34
--- /dev/null
+++ b/tests/diagnostics/interfaces/anyvalue-size-validation.slang
@@ -0,0 +1,29 @@
+// anyvalue-size-validation.slang
+
+//DIAGNOSTIC_TEST:SIMPLE:-target cpp -stage compute -entry main -allow-dynamic-code
+
+[anyValueSize(8)]
+interface IInterface
+{
+ int doSomething();
+};
+
+struct S : IInterface
+{
+ uint a;
+ uint b;
+ uint c;
+ int doSomething() { return 5; }
+};
+
+T test<T:IInterface>(T s)
+{
+ return s;
+}
+
+[numthreads(4, 1, 1)]
+void main()
+{
+ S s;
+ test(s);
+} \ No newline at end of file
diff --git a/tests/diagnostics/interfaces/anyvalue-size-validation.slang.expected b/tests/diagnostics/interfaces/anyvalue-size-validation.slang.expected
new file mode 100644
index 000000000..e88b6bd5d
--- /dev/null
+++ b/tests/diagnostics/interfaces/anyvalue-size-validation.slang.expected
@@ -0,0 +1,6 @@
+result code = -1
+standard error = {
+tests/diagnostics/interfaces/anyvalue-size-validation.slang(11): error 41011: type 'S' does not fit in the size required by its conforming interface.
+}
+standard output = {
+}