summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-any-value-marshalling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-ir-any-value-marshalling.cpp')
-rw-r--r--source/slang/slang-ir-any-value-marshalling.cpp241
1 files changed, 222 insertions, 19 deletions
diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp
index cd76e4430..b88dd79d1 100644
--- a/source/slang/slang-ir-any-value-marshalling.cpp
+++ b/source/slang/slang-ir-any-value-marshalling.cpp
@@ -99,6 +99,33 @@ namespace Slang
sink->diagnose(concreteType->sourceLoc, Diagnostics::typeDoesNotFitAnyValueSize, concreteType);
}
}
+ void ensureOffsetAt4ByteBoundary()
+ {
+ if (intraFieldOffset)
+ {
+ fieldOffset++;
+ intraFieldOffset = 0;
+ }
+ }
+ void ensureOffsetAt2ByteBoundary()
+ {
+ if (intraFieldOffset == 0)
+ return;
+ if (intraFieldOffset <= 2)
+ {
+ intraFieldOffset = 2;
+ return;
+ }
+ fieldOffset++;
+ intraFieldOffset = 0;
+ return;
+ }
+ void advanceOffset(uint32_t bytes)
+ {
+ intraFieldOffset += bytes;
+ fieldOffset += intraFieldOffset / 4;
+ intraFieldOffset = intraFieldOffset % 4;
+ }
};
void emitMarshallingCode(
@@ -208,6 +235,7 @@ namespace Slang
case kIROp_IntType:
case kIROp_FloatType:
{
+ ensureOffsetAt4ByteBoundary();
if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
{
auto srcVal = builder->emitLoad(concreteVar);
@@ -218,11 +246,12 @@ namespace Slang
anyValInfo->fieldKeys[fieldOffset]);
builder->emitStore(dstAddr, dstVal);
}
- fieldOffset++;
+ advanceOffset(4);
break;
}
case kIROp_UIntType:
{
+ ensureOffsetAt4ByteBoundary();
if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
{
auto srcVal = builder->emitLoad(concreteVar);
@@ -232,17 +261,56 @@ namespace Slang
anyValInfo->fieldKeys[fieldOffset]);
builder->emitStore(dstAddr, srcVal);
}
- fieldOffset++;
+ advanceOffset(4);
+ break;
+ }
+ case kIROp_Int16Type:
+ case kIROp_UInt16Type:
+ case kIROp_HalfType:
+ {
+ ensureOffsetAt2ByteBoundary();
+ if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
+ {
+ auto srcVal = builder->emitLoad(concreteVar);
+ if (dataType->getOp() == kIROp_HalfType)
+ {
+ srcVal = builder->emitBitCast(builder->getType(kIROp_UInt16Type), srcVal);
+ }
+ srcVal = builder->emitConstructorInst(builder->getType(kIROp_UIntType), 1, &srcVal);
+ auto dstAddr = builder->emitFieldAddress(
+ uintPtrType,
+ anyValueVar,
+ anyValInfo->fieldKeys[fieldOffset]);
+ auto dstVal = builder->emitLoad(dstAddr);
+ if (intraFieldOffset == 0)
+ {
+ srcVal = builder->emitBitAnd(
+ srcVal->getFullType(), srcVal,
+ builder->getIntValue(builder->getUIntType(), 0xFFFF));
+ dstVal = builder->emitBitAnd(
+ dstVal->getFullType(), dstVal,
+ builder->getIntValue(builder->getUIntType(), 0xFFFF0000));
+ }
+ else
+ {
+ srcVal = builder->emitShl(
+ srcVal->getFullType(), srcVal,
+ builder->getIntValue(builder->getUIntType(), 16));
+ dstVal = builder->emitBitAnd(
+ dstVal->getFullType(), dstVal,
+ builder->getIntValue(builder->getUIntType(), 0xFFFF));
+ }
+ dstVal = builder->emitBitOr(dstVal->getFullType(), dstVal, srcVal);
+ builder->emitStore(dstAddr, dstVal);
+ }
+ advanceOffset(2);
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:
@@ -253,6 +321,7 @@ namespace Slang
virtual void marshalResourceHandle(IRBuilder* builder, IRType* dataType, IRInst* concreteVar) override
{
SLANG_UNUSED(dataType);
+ ensureOffsetAt4ByteBoundary();
if (fieldOffset + 1 < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
{
auto srcVal = builder->emitLoad(concreteVar);
@@ -269,7 +338,7 @@ namespace Slang
auto dstAddr2 = builder->emitFieldAddress(
uintPtrType, anyValueVar, anyValInfo->fieldKeys[fieldOffset + 1]);
builder->emitStore(dstAddr2, highBits);
- fieldOffset += 2;
+ advanceOffset(8);
}
}
};
@@ -302,6 +371,13 @@ namespace Slang
builder.emitStore(concreteTypedVar, param);
auto resultVar = builder.emitVar(anyValInfo->type);
+ // Initialize fields to 0 to prevent downstream compiler error.
+ for (uint32_t offset = 0; offset < (uint32_t)anyValInfo->fieldKeys.getCount(); offset++)
+ {
+ auto fieldAddr = builder.emitFieldAddress(builder.getUIntType(), resultVar, anyValInfo->fieldKeys[offset]);
+ builder.emitStore(fieldAddr, builder.getIntValue(builder.getUIntType(), 0));
+ }
+
TypePackingContext context;
context.anyValInfo = anyValInfo;
context.fieldOffset = context.intraFieldOffset = 0;
@@ -311,13 +387,6 @@ namespace Slang
context.validateAnyTypeSize(sharedContext->sink, type);
- // Initialize the rest of unused fields to 0 to prevent downstream compiler error.
- for (uint32_t offset = context.fieldOffset; offset < (uint32_t)anyValInfo->fieldKeys.getCount(); offset++)
- {
- auto fieldAddr = builder.emitFieldAddress(builder.getUIntType(), resultVar, context.anyValInfo->fieldKeys[offset]);
- builder.emitStore(fieldAddr, builder.getIntValue(builder.getUIntType(), 0));
- }
-
auto load = builder.emitLoad(resultVar);
builder.emitReturn(load);
return func;
@@ -332,6 +401,7 @@ namespace Slang
case kIROp_IntType:
case kIROp_FloatType:
{
+ ensureOffsetAt4ByteBoundary();
if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
{
auto srcAddr = builder->emitFieldAddress(
@@ -342,11 +412,12 @@ namespace Slang
srcVal = builder->emitBitCast(dataType, srcVal);
builder->emitStore(concreteVar, srcVal);
}
- fieldOffset++;
+ advanceOffset(4);
break;
}
case kIROp_UIntType:
{
+ ensureOffsetAt4ByteBoundary();
if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
{
auto srcAddr = builder->emitFieldAddress(
@@ -356,17 +427,55 @@ namespace Slang
auto srcVal = builder->emitLoad(srcAddr);
builder->emitStore(concreteVar, srcVal);
}
- fieldOffset++;
+ advanceOffset(4);
+ break;
+ }
+ case kIROp_Int16Type:
+ case kIROp_UInt16Type:
+ case kIROp_HalfType:
+ {
+ ensureOffsetAt2ByteBoundary();
+ if (fieldOffset < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
+ {
+ auto srcAddr = builder->emitFieldAddress(
+ uintPtrType,
+ anyValueVar,
+ anyValInfo->fieldKeys[fieldOffset]);
+ auto srcVal = builder->emitLoad(srcAddr);
+ if (intraFieldOffset == 0)
+ {
+ srcVal = builder->emitBitAnd(
+ srcVal->getFullType(), srcVal,
+ builder->getIntValue(builder->getUIntType(), 0xFFFF));
+ }
+ else
+ {
+ srcVal = builder->emitShr(
+ srcVal->getFullType(), srcVal,
+ builder->getIntValue(builder->getUIntType(), 16));
+ }
+ if (dataType->getOp() == kIROp_Int16Type)
+ {
+ srcVal = builder->emitConstructorInst(builder->getType(kIROp_Int16Type), 1, &srcVal);
+ }
+ else
+ {
+ srcVal = builder->emitConstructorInst(builder->getType(kIROp_UInt16Type), 1, &srcVal);
+ }
+ if (dataType->getOp() == kIROp_HalfType)
+ {
+ srcVal = builder->emitBitCast(dataType, srcVal);
+ }
+ builder->emitStore(concreteVar, srcVal);
+ }
+ advanceOffset(2);
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:
@@ -377,6 +486,7 @@ namespace Slang
virtual void marshalResourceHandle(
IRBuilder* builder, IRType* dataType, IRInst* concreteVar) override
{
+ ensureOffsetAt4ByteBoundary();
if (fieldOffset + 1 < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount()))
{
auto srcAddr = builder->emitFieldAddress(
@@ -390,7 +500,7 @@ namespace Slang
auto combinedBits = builder->emitMakeUInt64(lowBits, highBits);
combinedBits = builder->emitBitCast(dataType, combinedBits);
builder->emitStore(concreteVar, combinedBits);
- fieldOffset += 2;
+ advanceOffset(8);
}
}
};
@@ -541,4 +651,97 @@ namespace Slang
context.sharedContext = sharedContext;
context.processModule();
}
+
+ SlangInt alignUp(SlangInt x, SlangInt alignment)
+ {
+ return (x + alignment - 1) / alignment * alignment;
+ }
+
+ SlangInt _getAnyValueSizeRaw(IRType* type, SlangInt offset)
+ {
+ switch (type->getOp())
+ {
+ case kIROp_IntType:
+ case kIROp_FloatType:
+ case kIROp_UIntType:
+ return alignUp(offset, 4) + 4;
+ case kIROp_UInt64Type:
+ case kIROp_Int64Type:
+ case kIROp_DoubleType:
+ return -1;
+ case kIROp_Int16Type:
+ case kIROp_UInt16Type:
+ case kIROp_HalfType:
+ return alignUp(offset, 2) + 2;
+ case kIROp_UInt8Type:
+ case kIROp_Int8Type:
+ return -1;
+ case kIROp_VectorType:
+ {
+ auto vectorType = static_cast<IRVectorType*>(type);
+ auto elementType = vectorType->getElementType();
+ auto elementCount = getIntVal(vectorType->getElementCount());
+ for (IRIntegerValue i = 0; i < elementCount; i++)
+ {
+ offset = _getAnyValueSizeRaw(elementType, offset);
+ if (offset < 0) return offset;
+ }
+ return offset;
+ }
+ case kIROp_MatrixType:
+ {
+ auto matrixType = static_cast<IRMatrixType*>(type);
+ auto elementType = matrixType->getElementType();
+ auto colCount = getIntVal(matrixType->getColumnCount());
+ auto rowCount = getIntVal(matrixType->getRowCount());
+ for (IRIntegerValue i = 0; i < colCount; i++)
+ {
+ for (IRIntegerValue j = 0; j < rowCount; j++)
+ {
+ offset = _getAnyValueSizeRaw(elementType, offset);
+ if (offset < 0) return offset;
+ }
+ }
+ return offset;
+ }
+ case kIROp_StructType:
+ {
+ auto structType = cast<IRStructType>(type);
+ for (auto field : structType->getFields())
+ {
+ offset = _getAnyValueSizeRaw(field->getFieldType(), offset);
+ if (offset < 0) return offset;
+ }
+ return offset;
+ }
+ case kIROp_ArrayType:
+ {
+ auto arrayType = cast<IRArrayType>(type);
+ for (IRIntegerValue i = 0; i < getIntVal(arrayType->getElementCount()); i++)
+ {
+ offset = _getAnyValueSizeRaw(arrayType->getElementType(), offset);
+ if (offset < 0) return offset;
+ }
+ return offset;
+ }
+ case kIROp_InterfaceType:
+ {
+ // TODO: implement anyValue packing for interface types.
+ return -1;
+ }
+ default:
+ if (as<IRTextureTypeBase>(type) || as<IRSamplerStateTypeBase>(type))
+ {
+ return alignUp(offset, 4) + 8;
+ }
+ return -1;
+ }
+ }
+
+ SlangInt getAnyValueSize(IRType* type)
+ {
+ auto rawSize = _getAnyValueSizeRaw(type, 0);
+ if (rawSize < 0) return rawSize;
+ return alignUp(rawSize, 4);
+ }
}