From 7d44ee78afc4a0f22b81b0b1e802c8d888e33f0f Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Thu, 5 Sep 2024 18:22:19 -0600 Subject: [PATCH 01/17] promoting bitfield extraction and insertion to become intrinsics for internal compiler use --- source/slang/core.meta.slang | 13 ++ source/slang/glsl.meta.slang | 34 ++-- source/slang/slang-emit-c-like.cpp | 171 ++++++++++++++++++ source/slang/slang-emit-c-like.h | 4 + source/slang/slang-emit-glsl.cpp | 22 +++ source/slang/slang-emit-glsl.h | 3 + source/slang/slang-emit-spirv.cpp | 48 +++++ .../slang/slang-ir-any-value-marshalling.cpp | 13 +- source/slang/slang-ir-inst-defs.h | 3 + source/slang/slang-ir-insts.h | 4 + source/slang/slang-ir.cpp | 35 ++++ 11 files changed, 332 insertions(+), 18 deletions(-) diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 4e85296664..5c72de6dea 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -2193,6 +2193,19 @@ __generic __intrinsic_op($(kIROp_Reinterpret)) T reinterpret(U value); +// Bitfield extract / insert +__generic +[__readNone] +[__unsafeForceInlineEarly] +__intrinsic_op($(kIROp_BitfieldInsert)) + T bitfieldInsert(T base, T insert, int offset, int bits); + +__generic +[__readNone] +[__unsafeForceInlineEarly] +__intrinsic_op($(kIROp_BitfieldExtract)) + T bitfieldExtract(T value, int offset, int bits); + // Use an otherwise unused value // // This can be used to silence the warning about returning before initializing an out paramter. diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index 0078d39cb2..ebfd41dc33 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -1247,48 +1247,50 @@ public uint bitfieldInsert(uint base, uint insert, int offset, int bits) } } -__generic [__readNone] [ForceInline] [require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public vector bitfieldInsert(vector base, vector insert, int offset, int bits) +public int bitfieldInsert(int base, int insert, int offset, int bits) { __target_switch { case glsl: __intrinsic_asm "bitfieldInsert"; case spirv: return spirv_asm { - result:$$vector = OpBitFieldInsert $base $insert $offset $bits + result:$$int = OpBitFieldInsert $base $insert $offset $bits }; default: - vector result; - [ForceUnroll] - for (int i = 0; i < N; ++i) - { - result[i] = bitfieldInsert(base[i], insert[i], offset, bits); - } - return result; + uint clearMask = ~(((1u << bits) - 1u) << offset); + uint clearedBase = base & clearMask; + uint maskedInsert = (insert & ((1u << bits) - 1u)) << offset; + return clearedBase | maskedInsert; } } +__generic [__readNone] [ForceInline] [require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public int bitfieldInsert(int base, int insert, int offset, int bits) +public vector bitfieldInsert(vector base, vector insert, int offset, int bits) { __target_switch { case glsl: __intrinsic_asm "bitfieldInsert"; case spirv: return spirv_asm { - result:$$int = OpBitFieldInsert $base $insert $offset $bits + result:$$vector = OpBitFieldInsert $base $insert $offset $bits }; default: - uint clearMask = ~(((1u << bits) - 1u) << offset); - uint clearedBase = base & clearMask; - uint maskedInsert = (insert & ((1u << bits) - 1u)) << offset; - return clearedBase | maskedInsert; + vector result; + [ForceUnroll] + for (int i = 0; i < N; ++i) + { + result[i] = bitfieldInsert(base[i], insert[i], offset, bits); + } + return result; } } + + __generic [__readNone] [ForceInline] diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 1893929f89..50258e579e 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -2762,6 +2762,16 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO m_writer->emit(")"); break; } + case kIROp_BitfieldExtract: + { + emitBitfieldExtractImpl(inst); + break; + } + case kIROp_BitfieldInsert: + { + emitBitfieldInsertImpl(inst); + break; + } case kIROp_PackAnyValue: { m_writer->emit("packAnyValue<"); @@ -3667,6 +3677,167 @@ void CLikeSourceEmitter::emitFuncDecorationsImpl(IRFunc* func) } } +bool CLikeSourceEmitter::tryEmitUnsignedEquivalent(IRType* dataType) +{ + IRVectorType* vectorType = as(dataType); + if (vectorType) + { + dataType = vectorType->getElementType(); + m_writer->emit("vector<"); + } + + Slang::IROp uType; + switch (dataType->getOp()) + { + case kIROp_UInt8Type: + case kIROp_Int8Type: + uType = kIROp_UInt8Type; + break; + case kIROp_UInt16Type: + case kIROp_Int16Type: + uType = kIROp_UInt16Type; + break; + case kIROp_UInt64Type: + case kIROp_Int64Type: + uType = kIROp_UInt64Type; + break; + case kIROp_UIntType: + case kIROp_IntType: + uType = kIROp_UIntType; + break; + default: + return false; + } + + m_writer->emit(getDefaultBuiltinTypeName(uType)); + + if (vectorType) + { + m_writer->emit(","); + emitSimpleValueImpl(vectorType->getElementCount()); + m_writer->emit(">"); + } + return true; +} + +void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) +{ + // BitfieldExtraction := T(uint(val>>off)&((1u<getDataType(); + Slang::IRInst* val = inst->getOperand(0); + Slang::IRInst* off = inst->getOperand(1); + Slang::IRInst* bts = inst->getOperand(2); + + // cast to the target type for optional sign extension + emitType(inst->getDataType()); + m_writer->emit("("); + { + // emit uint(val>>off) + if (!tryEmitUnsignedEquivalent(dataType)) + { + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldExtract"); + return; + } + m_writer->emit("("); + { + emitOperand(val, getInfo(EmitOp::General)); + m_writer->emit(">>"); + emitOperand(off, getInfo(EmitOp::General)); + } + m_writer->emit(")"); + + m_writer->emit("&"); + + // emit "((1u<emit("("); + { + // emit "(1u << bts) - 1" + m_writer->emit("(1u <<"); + emitOperand(bts, getInfo(EmitOp::General)); + m_writer->emit(") - 1"); + } + m_writer->emit(")"); + } + m_writer->emit(")"); +} + +void CLikeSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) { + // uint clearMask = ~(((1u << bits) - 1u) << offset); + // uint clearedBase = base & clearMask; + // uint maskedInsert = (insert & ((1u << bits) - 1u)) << offset; + // BitfieldInsert := T(uint(clearedBase) | uint(maskedInsert)); + Slang::IRType* dataType = inst->getDataType(); + Slang::IRInst* bse = inst->getOperand(0); + Slang::IRInst* ins = inst->getOperand(1); + Slang::IRInst* off = inst->getOperand(2); + Slang::IRInst* bts = inst->getOperand(3); + + // cast back to the target type + emitType(inst->getDataType()); + m_writer->emit("("); + { + // emit clearedBase := uint(base & clearMask) + if (!tryEmitUnsignedEquivalent(dataType)) + { + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldInsert"); + return; + } + m_writer->emit("("); + { + // emit base + emitOperand(bse, getInfo(EmitOp::General)); + m_writer->emit("&"); + + // emit clearMask := ~(((1u<emit("("); + { + m_writer->emit("~(((1u<<"); + emitOperand(bts, getInfo(EmitOp::General)); + m_writer->emit(")-1u)<<"); + emitOperand(off, getInfo(EmitOp::General)); + m_writer->emit(")"); + } + m_writer->emit(")"); + } + m_writer->emit(")"); + + // bitwise or clearedBase with maskedInsert + m_writer->emit("|"); + + // Emit maskedInsert := uint((insert & ((1u << bits) - 1u)) << offset); + if (!tryEmitUnsignedEquivalent(dataType)) + { + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldInsert"); + return; + } + m_writer->emit("("); + { + // Emit mask := (insert & ((1u << bits) - 1u)) + m_writer->emit("("); + { + // emit "insert & ((1u << bits) - 1u)" + emitOperand(ins, getInfo(EmitOp::General)); + m_writer->emit("&"); + m_writer->emit("("); + { + // emit "(1u << bits) - 1u" + m_writer->emit("(1u<<"); + emitOperand(bts, getInfo(EmitOp::General)); + m_writer->emit(")-1u"); + } + m_writer->emit(")"); + } + m_writer->emit(")"); + + // Emit shift := << offset + m_writer->emit("<<"); + emitOperand(off, getInfo(EmitOp::General)); + } + m_writer->emit(")"); + } + m_writer->emit(")"); +} + void CLikeSourceEmitter::emitStruct(IRStructType* structType) { ensureTypePrelude(structType); diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index 00ad156d1d..5442353588 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -517,6 +517,10 @@ class CLikeSourceEmitter: public SourceEmitterBase virtual void emitFuncDecorationsImpl(IRFunc* func); + bool tryEmitUnsignedEquivalent(IRType* type); + virtual void emitBitfieldExtractImpl(IRInst* inst); + virtual void emitBitfieldInsertImpl(IRInst* inst); + // Only needed for glsl output with $ prefix intrinsics - so perhaps removable in the future virtual void emitTextureOrTextureSamplerTypeImpl(IRTextureTypeBase* type, char const* baseName) { SLANG_UNUSED(type); SLANG_UNUSED(baseName); } diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 56113409d3..df850f7df4 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -2449,6 +2449,28 @@ void GLSLSourceEmitter::emitFuncDecorationImpl(IRDecoration* decoration) } } +void GLSLSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) { + m_writer->emit("bitfieldExtract("); + emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); + m_writer->emit(","); + emitOperand(inst->getOperand(1), getInfo(EmitOp::General)); + m_writer->emit(","); + emitOperand(inst->getOperand(2), getInfo(EmitOp::General)); + m_writer->emit(")"); +} + +void GLSLSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) { + m_writer->emit("bitfieldInsert("); + emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); + m_writer->emit(","); + emitOperand(inst->getOperand(1), getInfo(EmitOp::General)); + m_writer->emit(","); + emitOperand(inst->getOperand(2), getInfo(EmitOp::General)); + m_writer->emit(","); + emitOperand(inst->getOperand(3), getInfo(EmitOp::General)); + m_writer->emit(")"); +} + void GLSLSourceEmitter::emitSimpleTypeImpl(IRType* type) { switch (type->getOp()) diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h index 8958c7608e..569d4d783f 100644 --- a/source/slang/slang-emit-glsl.h +++ b/source/slang/slang-emit-glsl.h @@ -48,6 +48,9 @@ class GLSLSourceEmitter : public CLikeSourceEmitter virtual void emitFuncDecorationImpl(IRDecoration* decoration) SLANG_OVERRIDE; virtual void emitGlobalParamDefaultVal(IRGlobalParam* decl) SLANG_OVERRIDE; + virtual void emitBitfieldExtractImpl(IRInst* inst) SLANG_OVERRIDE; + virtual void emitBitfieldInsertImpl(IRInst* inst) SLANG_OVERRIDE; + virtual void handleRequiredCapabilitiesImpl(IRInst* inst) SLANG_OVERRIDE; virtual bool tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType) SLANG_OVERRIDE; diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index a2da4801e7..2bde48d45e 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -2971,6 +2971,12 @@ struct SPIRVEmitContext inst->getOperand(0) ); break; + case kIROp_BitfieldExtract: + result = emitBitfieldExtract(parent, inst); + break; + case kIROp_BitfieldInsert: + result = emitBitfieldInsert(parent, inst); + break; case kIROp_Add: case kIROp_Sub: case kIROp_Mul: @@ -5594,6 +5600,48 @@ struct SPIRVEmitContext return emitInst(parent, inst, SpvOpConvertUToPtr, inst->getFullType(), kResultID, inst->getOperand(0)); } + SpvInst* emitBitfieldExtract(SpvInstParent* parent, IRInst* inst) { + auto dataType = inst->getDataType(); + IRVectorType* vectorType = as(dataType); + if (vectorType) + { + dataType = vectorType->getElementType(); + } + + switch (dataType->getOp()) + { + case kIROp_UIntType: + return emitInst(parent, inst, SpvOpBitFieldUExtract, inst->getFullType(), kResultID, + inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); + case kIROp_IntType: + return emitInst(parent, inst, SpvOpBitFieldSExtract, inst->getFullType(), kResultID, + inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); + default: + SLANG_UNEXPECTED("type given to bitfieldExtract in SPIR-V emit"); + } + UNREACHABLE_RETURN(nullptr); + } + + SpvInst* emitBitfieldInsert(SpvInstParent* parent, IRInst* inst) { + auto dataType = inst->getDataType(); + IRVectorType* vectorType = as(dataType); + if (vectorType) + { + dataType = vectorType->getElementType(); + } + + switch (dataType->getOp()) + { + case kIROp_UIntType: + case kIROp_IntType: + return emitInst(parent, inst, SpvOpBitFieldInsert, inst->getFullType(), kResultID, + inst->getOperand(0), inst->getOperand(1), inst->getOperand(2), inst->getOperand(3)); + default: + SLANG_UNEXPECTED("type given to bitfieldInsert in SPIR-V emit"); + } + UNREACHABLE_RETURN(nullptr); + } + template SpvInst* emitCompositeConstruct( SpvInstParent* parent, diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp index f09294aa98..e89a26c6bf 100644 --- a/source/slang/slang-ir-any-value-marshalling.cpp +++ b/source/slang/slang-ir-any-value-marshalling.cpp @@ -327,8 +327,12 @@ namespace Slang } case kIROp_Int8Type: case kIROp_UInt8Type: + SLANG_UNIMPLEMENTED_X("AnyValue type packing for 8-bit elements"); + break; case kIROp_UInt64Type: case kIROp_Int64Type: + SLANG_UNIMPLEMENTED_X("AnyValue type packing for 64-bit elements"); + break; case kIROp_DoubleType: #if SLANG_PTR_IS_64 case kIROp_UIntPtrType: @@ -514,9 +518,13 @@ namespace Slang case kIROp_UInt64Type: case kIROp_Int64Type: case kIROp_DoubleType: + { + SLANG_UNIMPLEMENTED_X("AnyValue type unpacking for 64-bit elements"); + break; + } case kIROp_Int8Type: case kIROp_UInt8Type: - SLANG_UNIMPLEMENTED_X("AnyValue type packing for non 32-bit elements"); + SLANG_UNIMPLEMENTED_X("AnyValue type unpacking for 8-bit elements"); break; default: SLANG_UNREACHABLE("unknown basic type"); @@ -698,6 +706,7 @@ namespace Slang return alignUp(offset, 4) + 4; case kIROp_UInt64Type: case kIROp_Int64Type: + return alignUp(offset, 8) + 8; case kIROp_DoubleType: return -1; case kIROp_Int16Type: @@ -706,7 +715,7 @@ namespace Slang return alignUp(offset, 2) + 2; case kIROp_UInt8Type: case kIROp_Int8Type: - return -1; + return alignUp(offset, 1) + 1; case kIROp_VectorType: { auto vectorType = static_cast(type); diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index afc09f4801..74fdbe488d 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -379,6 +379,9 @@ INST(Alloca, alloca, 1, 0) INST(UpdateElement, updateElement, 2, 0) INST(DetachDerivative, detachDerivative, 1, 0) +INST(BitfieldExtract, bitfieldExtract, 3, 0) +INST(BitfieldInsert, bitfieldInsert, 4, 0) + INST(PackAnyValue, packAnyValue, 1, 0) INST(UnpackAnyValue, unpackAnyValue, 1, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index a0ed8ff0e7..3a8b6efc96 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -3820,6 +3820,10 @@ struct IRBuilder IRInst* emitGlobalValueRef(IRInst* globalInst); + IRInst* emitBitfieldExtract(IRType* type, IRInst* op0, IRInst* op1, IRInst* op2); + + IRInst* emitBitfieldInsert(IRType* type, IRInst* op0, IRInst* op1, IRInst* op2, IRInst* op3); + IRInst* emitPackAnyValue(IRType* type, IRInst* value); IRInst* emitUnpackAnyValue(IRType* type, IRInst* value); diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 9305d17830..f9f5f696c1 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -1980,6 +1980,25 @@ namespace Slang &args[0]); } + template + static T* createInst( + IRBuilder* builder, + IROp op, + IRType* type, + IRInst* arg1, + IRInst* arg2, + IRInst* arg3, + IRInst* arg4) + { + IRInst* args[] = { arg1, arg2, arg3, arg4 }; + return createInstImpl( + builder, + op, + type, + 4, + &args[0]); + } + template static T* createInstWithTrailingArgs( IRBuilder* builder, @@ -3632,6 +3651,20 @@ namespace Slang return inst; } + IRInst* IRBuilder::emitBitfieldExtract(IRType* type, IRInst* value, IRInst* offset, IRInst* bits) + { + auto inst = createInst(this, kIROp_BitfieldExtract, type, value, offset, bits); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitBitfieldInsert(IRType* type, IRInst* base, IRInst* insert, IRInst* offset, IRInst* bits) + { + auto inst = createInst(this, kIROp_BitfieldInsert, type, base, insert, offset, bits); + addInst(inst); + return inst; + } + IRInst* IRBuilder::emitPackAnyValue(IRType* type, IRInst* value) { auto inst = createInst( @@ -8452,6 +8485,8 @@ namespace Slang case kIROp_PtrCast: case kIROp_CastDynamicResource: case kIROp_AllocObj: + case kIROp_BitfieldExtract: + case kIROp_BitfieldInsert: case kIROp_PackAnyValue: case kIROp_UnpackAnyValue: case kIROp_Reinterpret: From 554b4f0b9780166626b046a27feb69e53f68d92d Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Thu, 5 Sep 2024 18:24:59 -0600 Subject: [PATCH 02/17] removing duplicate intrinsics from glsl.meta.slang --- source/slang/glsl.meta.slang | 164 ----------------------------------- 1 file changed, 164 deletions(-) diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index ebfd41dc33..6f7a12c5a3 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -1150,170 +1150,6 @@ public void imulExtended(highp vector x, highp vector y, out highp } } -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public int bitfieldExtract(int value, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldExtract"; - case spirv: return spirv_asm { - result:$$int = OpBitFieldSExtract $value $offset $bits - }; - default: - return int(uint(value >> offset) & ((1u << bits) - 1)); - } -} - -__generic -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public vector bitfieldExtract(vector value, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldExtract"; - case spirv: return spirv_asm { - result:$$vector = OpBitFieldSExtract $value $offset $bits - }; - default: - vector result; - [ForceUnroll] - for (int i = 0; i < N; ++i) - { - result[i] = bitfieldExtract(value[i], offset, bits); - } - return result; - } -} - -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public uint bitfieldExtract(uint value, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldExtract"; - case spirv: return spirv_asm { - result:$$uint = OpBitFieldUExtract $value $offset $bits - }; - default: - return (value >> offset) & ((1u << bits) - 1); - } -} - -__generic -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public vector bitfieldExtract(vector value, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldExtract"; - case spirv: return spirv_asm { - result:$$vector = OpBitFieldUExtract $value $offset $bits - }; - default: - vector result; - [ForceUnroll] - for (int i = 0; i < N; ++i) - { - result[i] = bitfieldExtract(value[i], offset, bits); - } - return result; - } -} - -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public uint bitfieldInsert(uint base, uint insert, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldInsert"; - case spirv: return spirv_asm { - result:$$uint = OpBitFieldInsert $base $insert $offset $bits - }; - default: - uint clearMask = ~(((1u << bits) - 1u) << offset); - uint clearedBase = base & clearMask; - uint maskedInsert = (insert & ((1u << bits) - 1u)) << offset; - return clearedBase | maskedInsert; - } -} - -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public int bitfieldInsert(int base, int insert, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldInsert"; - case spirv: return spirv_asm { - result:$$int = OpBitFieldInsert $base $insert $offset $bits - }; - default: - uint clearMask = ~(((1u << bits) - 1u) << offset); - uint clearedBase = base & clearMask; - uint maskedInsert = (insert & ((1u << bits) - 1u)) << offset; - return clearedBase | maskedInsert; - } -} - -__generic -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public vector bitfieldInsert(vector base, vector insert, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldInsert"; - case spirv: return spirv_asm { - result:$$vector = OpBitFieldInsert $base $insert $offset $bits - }; - default: - vector result; - [ForceUnroll] - for (int i = 0; i < N; ++i) - { - result[i] = bitfieldInsert(base[i], insert[i], offset, bits); - } - return result; - } -} - - - -__generic -[__readNone] -[ForceInline] -[require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] -public vector bitfieldInsert(vector base, vector insert, int offset, int bits) -{ - __target_switch - { - case glsl: __intrinsic_asm "bitfieldInsert"; - case spirv: return spirv_asm { - result:$$vector = OpBitFieldInsert $base $insert $offset $bits - }; - default: - vector result; - [ForceUnroll] - for (int i = 0; i < N; ++i) - { - result[i] = bitfieldInsert(base[i], insert[i], offset, bits); - } - return result; - } -} - [__readNone] [ForceInline] [require(cpp_cuda_glsl_hlsl_spirv, GLSL_400)] From 7eccd6c46f8026f4a0b48bb90330d7dd79518bc7 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Thu, 5 Sep 2024 18:27:37 -0600 Subject: [PATCH 03/17] reverting some unwanted changes --- source/slang/slang-ir-any-value-marshalling.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp index e89a26c6bf..f09294aa98 100644 --- a/source/slang/slang-ir-any-value-marshalling.cpp +++ b/source/slang/slang-ir-any-value-marshalling.cpp @@ -327,12 +327,8 @@ namespace Slang } case kIROp_Int8Type: case kIROp_UInt8Type: - SLANG_UNIMPLEMENTED_X("AnyValue type packing for 8-bit elements"); - break; case kIROp_UInt64Type: case kIROp_Int64Type: - SLANG_UNIMPLEMENTED_X("AnyValue type packing for 64-bit elements"); - break; case kIROp_DoubleType: #if SLANG_PTR_IS_64 case kIROp_UIntPtrType: @@ -518,13 +514,9 @@ namespace Slang case kIROp_UInt64Type: case kIROp_Int64Type: case kIROp_DoubleType: - { - SLANG_UNIMPLEMENTED_X("AnyValue type unpacking for 64-bit elements"); - break; - } case kIROp_Int8Type: case kIROp_UInt8Type: - SLANG_UNIMPLEMENTED_X("AnyValue type unpacking for 8-bit elements"); + SLANG_UNIMPLEMENTED_X("AnyValue type packing for non 32-bit elements"); break; default: SLANG_UNREACHABLE("unknown basic type"); @@ -706,7 +698,6 @@ namespace Slang return alignUp(offset, 4) + 4; case kIROp_UInt64Type: case kIROp_Int64Type: - return alignUp(offset, 8) + 8; case kIROp_DoubleType: return -1; case kIROp_Int16Type: @@ -715,7 +706,7 @@ namespace Slang return alignUp(offset, 2) + 2; case kIROp_UInt8Type: case kIROp_Int8Type: - return alignUp(offset, 1) + 1; + return -1; case kIROp_VectorType: { auto vectorType = static_cast(type); From 1d6e26cf0a73dd9c82026d7306484a1fd9f7d0d7 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Fri, 6 Sep 2024 13:54:53 -0600 Subject: [PATCH 04/17] small formatting fixes --- source/slang/core.meta.slang | 4 ++-- source/slang/slang-emit-c-like.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 5c72de6dea..c15d3d8517 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -2198,13 +2198,13 @@ __generic [__readNone] [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_BitfieldInsert)) - T bitfieldInsert(T base, T insert, int offset, int bits); +T bitfieldInsert(T base, T insert, int offset, int bits); __generic [__readNone] [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_BitfieldExtract)) - T bitfieldExtract(T value, int offset, int bits); +T bitfieldExtract(T value, int offset, int bits); // Use an otherwise unused value // diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 50258e579e..ccc0a1dfc4 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3761,7 +3761,8 @@ void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) m_writer->emit(")"); } -void CLikeSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) { +void CLikeSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) +{ // uint clearMask = ~(((1u << bits) - 1u) << offset); // uint clearedBase = base & clearMask; // uint maskedInsert = (insert & ((1u << bits) - 1u)) << offset; From 783328f4fc2c05a6799c5ca5722f097eccbee7e8 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Fri, 6 Sep 2024 14:45:17 -0600 Subject: [PATCH 05/17] adding test for bitfield extract, currently failing the sign extension case --- .../bitfield/bitfield-extract.slang | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/language-feature/bitfield/bitfield-extract.slang diff --git a/tests/language-feature/bitfield/bitfield-extract.slang b/tests/language-feature/bitfield/bitfield-extract.slang new file mode 100644 index 0000000000..7ec2065267 --- /dev/null +++ b/tests/language-feature/bitfield/bitfield-extract.slang @@ -0,0 +1,23 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type + +// CHECK: 123 +// CHECK-NEXT: 4567 +// CHECK-NEXT: 0 +// CHECK-NEXT: 0 + +//TEST_INPUT:ubuffer(data=[1 2 3 4], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain() +{ + uint a = outputBuffer[0]; + uint b = outputBuffer[1]; + uint c = outputBuffer[2]; + uint d = outputBuffer[3]; + + outputBuffer[0] = a; + outputBuffer[1] = b; + outputBuffer[2] = c; + outputBuffer[3] = d; +} From 00804a1a81304219646bfc4e32f2d973a4f83114 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Sun, 8 Sep 2024 19:46:11 -0700 Subject: [PATCH 06/17] adding some tests for 32 bit and 64 bit bitfield insertion and extraction --- source/slang/slang-emit-c-like.cpp | 243 +++++++++++------- source/slang/slang-emit-c-like.h | 3 +- .../bitfield/bitfield-extract-i32.slang | 56 ++++ .../bitfield/bitfield-extract-i64.slang | 56 ++++ .../bitfield/bitfield-extract.slang | 23 -- .../bitfield/bitfield-insert-i32.slang | 43 ++++ .../bitfield/bitfield-insert-i64.slang | 42 +++ 7 files changed, 347 insertions(+), 119 deletions(-) create mode 100644 tests/language-feature/bitfield/bitfield-extract-i32.slang create mode 100644 tests/language-feature/bitfield/bitfield-extract-i64.slang delete mode 100644 tests/language-feature/bitfield/bitfield-extract.slang create mode 100644 tests/language-feature/bitfield/bitfield-insert-i32.slang create mode 100644 tests/language-feature/bitfield/bitfield-insert-i64.slang diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index ccc0a1dfc4..9c2547d21d 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3677,88 +3677,140 @@ void CLikeSourceEmitter::emitFuncDecorationsImpl(IRFunc* func) } } -bool CLikeSourceEmitter::tryEmitUnsignedEquivalent(IRType* dataType) +bool CLikeSourceEmitter::tryGetIntInfo(IRType* elementType, bool &isSigned, int &bitWidth) { - IRVectorType* vectorType = as(dataType); - if (vectorType) - { - dataType = vectorType->getElementType(); - m_writer->emit("vector<"); - } + Slang::IROp type = elementType->getOp(); + if (!(type >= kIROp_Int8Type && type <= kIROp_UInt64Type)) return false; + isSigned = (type >= kIROp_Int8Type && type <= kIROp_Int64Type); + + Slang::IROp stype = (isSigned) ? type : Slang::IROp(type - 4); + bitWidth = 8 << (stype - kIROp_Int8Type); + return true; +} - Slang::IROp uType; - switch (dataType->getOp()) +void CLikeSourceEmitter::emitVecNOrScalar(IRVectorType* vectorType, std::function emitComponentLogic) +{ + if (vectorType) { - case kIROp_UInt8Type: - case kIROp_Int8Type: - uType = kIROp_UInt8Type; - break; - case kIROp_UInt16Type: - case kIROp_Int16Type: - uType = kIROp_UInt16Type; - break; - case kIROp_UInt64Type: - case kIROp_Int64Type: - uType = kIROp_UInt64Type; - break; - case kIROp_UIntType: - case kIROp_IntType: - uType = kIROp_UIntType; - break; - default: - return false; - } + // Special handling required for CUDA target + if (isCUDATarget(getTargetReq())) + { + m_writer->emit("make_"); + Slang::IRType *elementType = vectorType->getElementType(); - m_writer->emit(getDefaultBuiltinTypeName(uType)); - - if (vectorType) + switch(elementType->getOp()) + { + case kIROp_Int8Type: m_writer->emit("char"); break; + case kIROp_Int16Type: m_writer->emit("short"); break; + case kIROp_IntType: m_writer->emit("int"); break; + case kIROp_Int64Type: m_writer->emit("longlong"); break; + case kIROp_UInt8Type: m_writer->emit("uchar"); break; + case kIROp_UInt16Type: m_writer->emit("ushort"); break; + case kIROp_UIntType: m_writer->emit("uint"); break; + case kIROp_UInt64Type: m_writer->emit("ulonglong"); break; + default: SLANG_ABORT_COMPILATION("Unhandled type emitting CUDA vector"); + } + + int N = int(getIntVal(vectorType->getElementCount())); + m_writer->emitRawText(std::to_string(N).c_str()); + m_writer->emit("("); + for (int i = 0; i < N; ++i) + { + emitType(elementType); + m_writer->emit("("); + emitComponentLogic(); + m_writer->emit(")"); + if (i != N - 1) + m_writer->emit(", "); + } + m_writer->emit(")"); + } + else + { + emitType(vectorType); + m_writer->emit("("); + emitComponentLogic(); + m_writer->emit(")"); + } + } + else { - m_writer->emit(","); - emitSimpleValueImpl(vectorType->getElementCount()); - m_writer->emit(">"); + m_writer->emit("("); + emitComponentLogic(); + m_writer->emit(")"); } - return true; } void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) { - // BitfieldExtraction := T(uint(val>>off)&((1u<>off)&((1u<>off)&((1u<>(nbts-bts)); Slang::IRType* dataType = inst->getDataType(); Slang::IRInst* val = inst->getOperand(0); Slang::IRInst* off = inst->getOperand(1); Slang::IRInst* bts = inst->getOperand(2); + + Slang::IRType* elementType = dataType; + IRVectorType* vectorType = as(elementType); + if (vectorType) + elementType = vectorType->getElementType(); + + bool isSigned; + int bitWidth; + if (!tryGetIntInfo(elementType, isSigned, bitWidth)) + { + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldExtract"); + return; + } - // cast to the target type for optional sign extension - emitType(inst->getDataType()); - m_writer->emit("("); + // Emit open paren and type cast for later sign extension + if (isSigned) { - // emit uint(val>>off) - if (!tryEmitUnsignedEquivalent(dataType)) - { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldExtract"); - return; - } m_writer->emit("("); - { - emitOperand(val, getInfo(EmitOp::General)); - m_writer->emit(">>"); - emitOperand(off, getInfo(EmitOp::General)); - } - m_writer->emit(")"); - - m_writer->emit("&"); + emitType(inst->getDataType()); + } - // emit "((1u<emit("("); + // Emit bitfield extraction ((val>>off)&((1u<emit("(("); + emitOperand(val, getInfo(EmitOp::General)); + m_writer->emit(">>"); + emitVecNOrScalar(vectorType, [&]() { + emitOperand(off, getInfo(EmitOp::General)); + }); + m_writer->emit(")&("); + emitVecNOrScalar(vectorType, [&]() { + if (bitWidth <= 32) m_writer->emit("((1u<<"); + else m_writer->emit("((1ull<<"); + emitOperand(bts, getInfo(EmitOp::General)); + m_writer->emit(")-1)"); + }); + m_writer->emit("))"); + + // Emit sign extension logic + // (bitfield<<(numBits-bts)>>(numBits-bts)) + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + if (isSigned) + { + m_writer->emit("<<"); + emitVecNOrScalar(vectorType, [&]() { - // emit "(1u << bts) - 1" - m_writer->emit("(1u <<"); + m_writer->emit("("); + m_writer->emit(bitWidth); + m_writer->emit("-"); emitOperand(bts, getInfo(EmitOp::General)); - m_writer->emit(") - 1"); - } + m_writer->emit(")"); + }); + m_writer->emit(">>"); + emitVecNOrScalar(vectorType, [&]() + { + m_writer->emit("("); + m_writer->emit(bitWidth); + m_writer->emit("-"); + emitOperand(bts, getInfo(EmitOp::General)); + m_writer->emit(")"); + }); m_writer->emit(")"); } - m_writer->emit(")"); } void CLikeSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) @@ -3773,66 +3825,67 @@ void CLikeSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) Slang::IRInst* off = inst->getOperand(2); Slang::IRInst* bts = inst->getOperand(3); - // cast back to the target type - emitType(inst->getDataType()); + Slang::IRType* elementType = dataType; + IRVectorType* vectorType = as(elementType); + if (vectorType) + elementType = vectorType->getElementType(); + + bool isSigned; + int bitWidth; + if (!tryGetIntInfo(elementType, isSigned, bitWidth)) + { + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldInsert"); + return; + } + m_writer->emit("("); { // emit clearedBase := uint(base & clearMask) - if (!tryEmitUnsignedEquivalent(dataType)) - { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldInsert"); - return; - } m_writer->emit("("); - { + { // emit base emitOperand(bse, getInfo(EmitOp::General)); m_writer->emit("&"); - + // emit clearMask := ~(((1u<emit("("); + emitVecNOrScalar(vectorType, [&]() { - m_writer->emit("~(((1u<<"); + if (bitWidth <= 32) m_writer->emit("~(((1u<<"); + else m_writer->emit("~(((1ull<<"); emitOperand(bts, getInfo(EmitOp::General)); - m_writer->emit(")-1u)<<"); + if (bitWidth <= 32) m_writer->emit(")-1u)<<"); + else m_writer->emit(")-1ull)<<"); emitOperand(off, getInfo(EmitOp::General)); m_writer->emit(")"); - } - m_writer->emit(")"); + }); } m_writer->emit(")"); // bitwise or clearedBase with maskedInsert m_writer->emit("|"); - // Emit maskedInsert := uint((insert & ((1u << bits) - 1u)) << offset); - if (!tryEmitUnsignedEquivalent(dataType)) - { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldInsert"); - return; - } + // Emit maskedInsert := ((insert & ((1u << bits) - 1u)) << offset); m_writer->emit("("); { // Emit mask := (insert & ((1u << bits) - 1u)) m_writer->emit("("); - { - // emit "insert & ((1u << bits) - 1u)" - emitOperand(ins, getInfo(EmitOp::General)); - m_writer->emit("&"); - m_writer->emit("("); - { - // emit "(1u << bits) - 1u" - m_writer->emit("(1u<<"); - emitOperand(bts, getInfo(EmitOp::General)); - m_writer->emit(")-1u"); - } - m_writer->emit(")"); - } + emitOperand(ins, getInfo(EmitOp::General)); + m_writer->emit("&"); + emitVecNOrScalar(vectorType, [&](){ + if (bitWidth <= 32) m_writer->emit("(1u<<"); + else m_writer->emit("(1ull<<"); + emitOperand(bts, getInfo(EmitOp::General)); + if (bitWidth <= 32) m_writer->emit(")-1u"); + else m_writer->emit(")-1ull"); + }); m_writer->emit(")"); - + // Emit shift := << offset m_writer->emit("<<"); - emitOperand(off, getInfo(EmitOp::General)); + + emitVecNOrScalar(vectorType, [&](){ + emitOperand(off, getInfo(EmitOp::General)); + }); } m_writer->emit(")"); } diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index 5442353588..3935f0e5bd 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -517,7 +517,8 @@ class CLikeSourceEmitter: public SourceEmitterBase virtual void emitFuncDecorationsImpl(IRFunc* func); - bool tryEmitUnsignedEquivalent(IRType* type); + bool tryGetIntInfo(IRType* elementType, bool &isSigned, int &bitWidth); + void emitVecNOrScalar(IRVectorType* vectorType, std::function func); virtual void emitBitfieldExtractImpl(IRInst* inst); virtual void emitBitfieldInsertImpl(IRInst* inst); diff --git a/tests/language-feature/bitfield/bitfield-extract-i32.slang b/tests/language-feature/bitfield/bitfield-extract-i32.slang new file mode 100644 index 0000000000..8a89d7a9e3 --- /dev/null +++ b/tests/language-feature/bitfield/bitfield-extract-i32.slang @@ -0,0 +1,56 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type + +// CHECK: 1 +// CHECK-NEXT: 2 +// CHECK-NEXT: 3 +// CHECK-NEXT: 4 +// CHECK-NEXT: 5 +// CHECK-NEXT: 6 +// CHECK-NEXT: 7 +// CHECK-NEXT: 8 +// CHECK-NEXT: 33 +// CHECK-NEXT: 122 +// CHECK-NEXT: -6 +// CHECK-NEXT: 10 +// CHECK-NEXT: 103 +// CHECK-NEXT: -17 +// CHECK-NEXT: 50 +// CHECK-NEXT: -87 + +//TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain() +{ + // Simple hex extraction to test, varying the offset. + uint value = 0x87654321; + outputBuffer[0] = bitfieldExtract(value, 4 * 0, 4); + outputBuffer[1] = bitfieldExtract(value, 4 * 1, 4); + outputBuffer[2] = bitfieldExtract(value, 4 * 2, 4); + outputBuffer[3] = bitfieldExtract(value, 4 * 3, 4); + outputBuffer[4] = bitfieldExtract(value, 4 * 4, 4); + outputBuffer[5] = bitfieldExtract(value, 4 * 5, 4); + outputBuffer[6] = bitfieldExtract(value, 4 * 6, 4); + outputBuffer[7] = bitfieldExtract(value, 4 * 7, 4); + + // Now varying the bit length + value = 0b00111011111011110001111010100001; + outputBuffer[8] = bitfieldExtract(value, 0, 6); + outputBuffer[9] = bitfieldExtract(value, 6, 8); + + // Sign extension case + // - For unsigned data types, the most significant bits of the result will be set to zero. + // - For signed data types, the most significant bits will be set to the value of bit offset + base - 1 + // (i.e., it is sign extended to the width of the return type). + outputBuffer[10] = bitfieldExtract(0b1010111, 3, 4); // 0b1010 -> 0b11111111111111111111111111111010 + outputBuffer[11] = bitfieldExtract(0b1010111u, 3, 4); // 0b1111 -> 0b00000000000000000000000000001010 + + // Component-wise extraction + int4 val4 = int4(0x12345678, 0x9abcdef0, 0x87654321, 0xfedcba98); + int4 ext4 = bitfieldExtract(val4, 4, 8); + outputBuffer[12] = ext4.x; + outputBuffer[13] = ext4.y; + outputBuffer[14] = ext4.z; + outputBuffer[15] = ext4.w; +} diff --git a/tests/language-feature/bitfield/bitfield-extract-i64.slang b/tests/language-feature/bitfield/bitfield-extract-i64.slang new file mode 100644 index 0000000000..00d9b17e7b --- /dev/null +++ b/tests/language-feature/bitfield/bitfield-extract-i64.slang @@ -0,0 +1,56 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type + +// CHECK: 0 +// CHECK-NEXT: 2 +// CHECK-NEXT: 4 +// CHECK-NEXT: 6 +// CHECK-NEXT: 8 +// CHECK-NEXT: 13 +// CHECK-NEXT: 11 +// CHECK-NEXT: 10 +// CHECK-NEXT: 444691369455 +// CHECK-NEXT: 10560325 +// CHECK-NEXT: 18446744073709551610 +// CHECK-NEXT: 10 +// CHECK-NEXT: 86 +// CHECK-NEXT: 18446744073709551582 +// CHECK-NEXT: 67 +// CHECK-NEXT: 18446744073709551546 + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=8):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain() +{ + // Simple hex extraction to test, varying the offset. + uint64_t value = 0xABCDEF9876543210ull; + outputBuffer[0] = bitfieldExtract(value, 4 * 0, 4); + outputBuffer[1] = bitfieldExtract(value, 4 * 2, 4); + outputBuffer[2] = bitfieldExtract(value, 4 * 4, 4); + outputBuffer[3] = bitfieldExtract(value, 4 * 6, 4); + outputBuffer[4] = bitfieldExtract(value, 4 * 8, 4); + outputBuffer[5] = bitfieldExtract(value, 4 * 12, 4); + outputBuffer[6] = bitfieldExtract(value, 4 * 14, 4); + outputBuffer[7] = bitfieldExtract(value, 4 * 15, 4); + + // Now varying the bit length + value = 0xA123456789ABCDEFull; + outputBuffer[8] = bitfieldExtract(value, 0, 40); // 0x6789ABCDEF + outputBuffer[9] = bitfieldExtract(value, 40, 24); // 0xA12345 + + // Sign extension case + // - For unsigned data types, the most significant bits of the result will be set to zero. + // - For signed data types, the most significant bits will be set to the value of bit offset + base - 1 + // (i.e., it is sign extended to the width of the return type). + outputBuffer[10] = bitfieldExtract(0b1010111ll, 3, 4); // 0b1010 -> 0b11111111111111111111111111111010 + outputBuffer[11] = bitfieldExtract(0b1010111ull, 3, 4); // 0b1010 -> 0b00000000000000000000000000001010 + + // Component-wise extraction + int64_t4 val4 = int64_t4(0x123456789abcdef0ll, 0x9abcdef012345678ll, 0x87654321fedcba98ll, 0xfedcba9876543210ll); + int64_t4 ext4 = bitfieldExtract(val4, 40, 8); + outputBuffer[12] = ext4.x; + outputBuffer[13] = ext4.y; + outputBuffer[14] = ext4.z; + outputBuffer[15] = ext4.w; +} diff --git a/tests/language-feature/bitfield/bitfield-extract.slang b/tests/language-feature/bitfield/bitfield-extract.slang deleted file mode 100644 index 7ec2065267..0000000000 --- a/tests/language-feature/bitfield/bitfield-extract.slang +++ /dev/null @@ -1,23 +0,0 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type - -// CHECK: 123 -// CHECK-NEXT: 4567 -// CHECK-NEXT: 0 -// CHECK-NEXT: 0 - -//TEST_INPUT:ubuffer(data=[1 2 3 4], stride=4):out,name=outputBuffer -RWStructuredBuffer outputBuffer; - -[numthreads(1, 1, 1)] -void computeMain() -{ - uint a = outputBuffer[0]; - uint b = outputBuffer[1]; - uint c = outputBuffer[2]; - uint d = outputBuffer[3]; - - outputBuffer[0] = a; - outputBuffer[1] = b; - outputBuffer[2] = c; - outputBuffer[3] = d; -} diff --git a/tests/language-feature/bitfield/bitfield-insert-i32.slang b/tests/language-feature/bitfield/bitfield-insert-i32.slang new file mode 100644 index 0000000000..14b2dfdcda --- /dev/null +++ b/tests/language-feature/bitfield/bitfield-insert-i32.slang @@ -0,0 +1,43 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type + +// CHECK: 2271560495 +// CHECK-NEXT: 2271560689 +// CHECK-NEXT: 2271563553 +// CHECK-NEXT: 2271605537 +// CHECK-NEXT: 168 +// CHECK-NEXT: 16320 +// CHECK-NEXT: 305420024 +// CHECK-NEXT: 2596068960 +// CHECK-NEXT: 2271560497 +// CHECK-NEXT: 4275878504 + +//TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain() +{ + // Simple hex insertion to test, varying the offset. + uint base = 0x87654321; + uint value = 0xABCDEF; + outputBuffer[0] = bitfieldInsert(base, value, 4 * 0, 4); // 0x8765432F -> 2271560495 + outputBuffer[1] = bitfieldInsert(base, value, 4 * 1, 4); // 0x876543F1 -> 2271560689 + outputBuffer[2] = bitfieldInsert(base, value, 4 * 2, 4); // 0x8765F321 -> 2271563553 + outputBuffer[3] = bitfieldInsert(base, value, 4 * 3, 4); // 0x87F54321 -> 2271605537 + + // Test with varying bit length + base = 0; + value = 0b101010; + outputBuffer[4] = bitfieldInsert(base, value, 2, 6); // 0b10101000 -> 1005526666 + value = 0b11111111; + outputBuffer[5] = bitfieldInsert(base, value, 6, 8); // 0b11111111000000 -> 1005519841 + + // Test with a vector + uint4 base4 = uint4(0x12345678, 0x9abcdef0, 0x87654321, 0xfedcba98); + uint4 value4 = uint4(0xABCDEF, 0x123456, 0x876543, 0x123456); + uint4 output4 = bitfieldInsert(base4, value4, 4, 4); + outputBuffer[6] = output4.x; + outputBuffer[7] = output4.y; + outputBuffer[8] = output4.z; + outputBuffer[9] = output4.w; +} diff --git a/tests/language-feature/bitfield/bitfield-insert-i64.slang b/tests/language-feature/bitfield/bitfield-insert-i64.slang new file mode 100644 index 0000000000..27a212a942 --- /dev/null +++ b/tests/language-feature/bitfield/bitfield-insert-i64.slang @@ -0,0 +1,42 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type + +// CHECK: 18364758544493064730 +// CHECK-NEXT: 18364758553082999312 +// CHECK-NEXT: 18364195594539643408 +// CHECK-NEXT: 12600151021458829840 +// CHECK-NEXT: 10477124133360 +// CHECK-NEXT: 16492674416640 +// CHECK-NEXT: 10477124133360 +// CHECK-NEXT: 10477124133360 +// CHECK-NEXT: 10477124133360 +// CHECK-NEXT: 10477124133360 + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=8):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain() +{ + // Simple hex insertion to test, varying the offset. + uint64_t base = 0xFEDCBA9876543210ull; + uint64_t insert = 0xAull; + outputBuffer[0] = bitfieldInsert(base, insert, 4 * 0, 4); // 0xFEDCBA987654321Aull -> 2271560495 + outputBuffer[1] = bitfieldInsert(base, insert, 4 * 8, 4); // 0xFEDCBA98A6543210ull -> 2271560689 + outputBuffer[2] = bitfieldInsert(base, insert, 4 * 12, 4); // 0xFEDCAA9876543210ull -> 2271563553 + outputBuffer[3] = bitfieldInsert(base, insert, 4 * 15, 4); // 0xAEDCBA9876543210ull -> 2271605537 + + // Test with varying bit length + base = 0; + insert = 0xFEDCBA987654321Full; + outputBuffer[4] = bitfieldInsert(base, insert, 4, 40); // 0xA987654321 -> 16492674416640 + outputBuffer[5] = bitfieldInsert(base, insert, 40, 4); // 0xF000000000 -> 10477124133360 + + // Test with a vector + uint64_t4 base4 = uint64_t4(base, base, base, base); + uint64_t4 insert4 = uint64_t4(insert, insert, insert, insert); + uint64_t4 output4 = bitfieldInsert(base4, insert4, 4, 40); + outputBuffer[6] = output4.x; + outputBuffer[7] = output4.y; + outputBuffer[8] = output4.z; + outputBuffer[9] = output4.w; +} From 648107ffa364f261b9bec4b9cbd4242beee3f259 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Mon, 9 Sep 2024 13:35:12 -0700 Subject: [PATCH 07/17] adding more targets to test. --- source/slang/slang-emit-c-like.cpp | 25 ++++------ .../bitfield/bitfield-extract-i32.slang | 24 ++++++---- .../bitfield/bitfield-extract-i64.slang | 46 +++++++++++++------ .../bitfield/bitfield-insert-i32.slang | 26 ++++++----- .../bitfield/bitfield-insert-i64.slang | 38 ++++++++++----- 5 files changed, 98 insertions(+), 61 deletions(-) diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 9c2547d21d..0d69a82312 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3692,11 +3692,13 @@ void CLikeSourceEmitter::emitVecNOrScalar(IRVectorType* vectorType, std::functio { if (vectorType) { + int N = int(getIntVal(vectorType->getElementCount())); + Slang::IRType *elementType = vectorType->getElementType(); + // Special handling required for CUDA target if (isCUDATarget(getTargetReq())) { m_writer->emit("make_"); - Slang::IRType *elementType = vectorType->getElementType(); switch(elementType->getOp()) { @@ -3711,27 +3713,20 @@ void CLikeSourceEmitter::emitVecNOrScalar(IRVectorType* vectorType, std::functio default: SLANG_ABORT_COMPILATION("Unhandled type emitting CUDA vector"); } - int N = int(getIntVal(vectorType->getElementCount())); m_writer->emitRawText(std::to_string(N).c_str()); - m_writer->emit("("); - for (int i = 0; i < N; ++i) - { - emitType(elementType); - m_writer->emit("("); - emitComponentLogic(); - m_writer->emit(")"); - if (i != N - 1) - m_writer->emit(", "); - } - m_writer->emit(")"); } - else + + m_writer->emit("("); + for (int i = 0; i < N; ++i) { - emitType(vectorType); + emitType(elementType); m_writer->emit("("); emitComponentLogic(); m_writer->emit(")"); + if (i != N - 1) + m_writer->emit(", "); } + m_writer->emit(")"); } else { diff --git a/tests/language-feature/bitfield/bitfield-extract-i32.slang b/tests/language-feature/bitfield/bitfield-extract-i32.slang index 8a89d7a9e3..8bbb9e3552 100644 --- a/tests/language-feature/bitfield/bitfield-extract-i32.slang +++ b/tests/language-feature/bitfield/bitfield-extract-i32.slang @@ -1,4 +1,8 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda // CHECK: 1 // CHECK-NEXT: 2 @@ -8,16 +12,16 @@ // CHECK-NEXT: 6 // CHECK-NEXT: 7 // CHECK-NEXT: 8 -// CHECK-NEXT: 33 -// CHECK-NEXT: 122 -// CHECK-NEXT: -6 -// CHECK-NEXT: 10 -// CHECK-NEXT: 103 -// CHECK-NEXT: -17 -// CHECK-NEXT: 50 -// CHECK-NEXT: -87 +// CHECK-NEXT: 21 +// CHECK-NEXT: 7A +// CHECK-NEXT: FFFFFFFA +// CHECK-NEXT: A +// CHECK-NEXT: 67 +// CHECK-NEXT: FFFFFFEF +// CHECK-NEXT: 32 +// CHECK-NEXT: FFFFFFA9 -//TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15], stride=4):out,name=outputBuffer +//TEST_INPUT:ubuffer(data=[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; [numthreads(1, 1, 1)] diff --git a/tests/language-feature/bitfield/bitfield-extract-i64.slang b/tests/language-feature/bitfield/bitfield-extract-i64.slang index 00d9b17e7b..2b8378c2f0 100644 --- a/tests/language-feature/bitfield/bitfield-extract-i64.slang +++ b/tests/language-feature/bitfield/bitfield-extract-i64.slang @@ -1,23 +1,43 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda -// CHECK: 0 +// CHECK: 0 +// CHECK-NEXT: 0 // CHECK-NEXT: 2 +// CHECK-NEXT: 0 // CHECK-NEXT: 4 +// CHECK-NEXT: 0 // CHECK-NEXT: 6 +// CHECK-NEXT: 0 // CHECK-NEXT: 8 -// CHECK-NEXT: 13 -// CHECK-NEXT: 11 -// CHECK-NEXT: 10 -// CHECK-NEXT: 444691369455 -// CHECK-NEXT: 10560325 -// CHECK-NEXT: 18446744073709551610 -// CHECK-NEXT: 10 -// CHECK-NEXT: 86 -// CHECK-NEXT: 18446744073709551582 +// CHECK-NEXT: 0 +// CHECK-NEXT: D +// CHECK-NEXT: 0 +// CHECK-NEXT: B +// CHECK-NEXT: 0 +// CHECK-NEXT: A +// CHECK-NEXT: 0 +// CHECK-NEXT: 89ABCDEF // CHECK-NEXT: 67 -// CHECK-NEXT: 18446744073709551546 +// CHECK-NEXT: A12345 +// CHECK-NEXT: 0 +// CHECK-NEXT: FFFFFFFA +// CHECK-NEXT: FFFFFFFF +// CHECK-NEXT: A +// CHECK-NEXT: 0 +// CHECK-NEXT: 56 +// CHECK-NEXT: 0 +// CHECK-NEXT: FFFFFFDE +// CHECK-NEXT: FFFFFFFF +// CHECK-NEXT: 43 +// CHECK-NEXT: 0 +// CHECK-NEXT: FFFFFFBA +// CHECK-NEXT: FFFFFFFF -//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=8):out,name=outputBuffer +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; [numthreads(1, 1, 1)] diff --git a/tests/language-feature/bitfield/bitfield-insert-i32.slang b/tests/language-feature/bitfield/bitfield-insert-i32.slang index 14b2dfdcda..dccac43cb0 100644 --- a/tests/language-feature/bitfield/bitfield-insert-i32.slang +++ b/tests/language-feature/bitfield/bitfield-insert-i32.slang @@ -1,15 +1,19 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda -// CHECK: 2271560495 -// CHECK-NEXT: 2271560689 -// CHECK-NEXT: 2271563553 -// CHECK-NEXT: 2271605537 -// CHECK-NEXT: 168 -// CHECK-NEXT: 16320 -// CHECK-NEXT: 305420024 -// CHECK-NEXT: 2596068960 -// CHECK-NEXT: 2271560497 -// CHECK-NEXT: 4275878504 +// CHECK: 8765432F +// CHECK-NEXT: 876543F1 +// CHECK-NEXT: 87654F21 +// CHECK-NEXT: 8765F321 +// CHECK-NEXT: A8 +// CHECK-NEXT: 3FC0 +// CHECK-NEXT: 123456F8 +// CHECK-NEXT: 9ABCDE60 +// CHECK-NEXT: 87654331 +// CHECK-NEXT: FEDCBA68 //TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; diff --git a/tests/language-feature/bitfield/bitfield-insert-i64.slang b/tests/language-feature/bitfield/bitfield-insert-i64.slang index 27a212a942..2f8942786f 100644 --- a/tests/language-feature/bitfield/bitfield-insert-i64.slang +++ b/tests/language-feature/bitfield/bitfield-insert-i64.slang @@ -1,17 +1,31 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda -// CHECK: 18364758544493064730 -// CHECK-NEXT: 18364758553082999312 -// CHECK-NEXT: 18364195594539643408 -// CHECK-NEXT: 12600151021458829840 -// CHECK-NEXT: 10477124133360 -// CHECK-NEXT: 16492674416640 -// CHECK-NEXT: 10477124133360 -// CHECK-NEXT: 10477124133360 -// CHECK-NEXT: 10477124133360 -// CHECK-NEXT: 10477124133360 +//CHECK: 7654321A +//CHECK-NEXT: FEDCBA98 +//CHECK-NEXT: 76543210 +//CHECK-NEXT: FEDCBA9A +//CHECK-NEXT: 76543210 +//CHECK-NEXT: FEDABA98 +//CHECK-NEXT: 76543210 +//CHECK-NEXT: AEDCBA98 +//CHECK-NEXT: 654321F0 +//CHECK-NEXT: 987 +//CHECK-NEXT: 0 +//CHECK-NEXT: F00 +//CHECK-NEXT: 654321F0 +//CHECK-NEXT: 987 +//CHECK-NEXT: 654321F0 +//CHECK-NEXT: 987 +//CHECK-NEXT: 654321F0 +//CHECK-NEXT: 987 +//CHECK-NEXT: 654321F0 +//CHECK-NEXT: 987 -//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=8):out,name=outputBuffer +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; [numthreads(1, 1, 1)] From a3529caa2ca76ecebe79d08fcf3d8061e0f425a5 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Tue, 10 Sep 2024 11:48:27 -0700 Subject: [PATCH 08/17] fixing small regression when emitting component-wise bitfield ops for CPU backend --- source/slang/slang-emit-c-like.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 0d69a82312..3361ec0574 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3715,6 +3715,9 @@ void CLikeSourceEmitter::emitVecNOrScalar(IRVectorType* vectorType, std::functio m_writer->emitRawText(std::to_string(N).c_str()); } + else { + emitType(vectorType); + } m_writer->emit("("); for (int i = 0; i < N; ++i) From d04bb68854632652774d296752685ce3f9f10803 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Tue, 10 Sep 2024 12:22:19 -0700 Subject: [PATCH 09/17] updating spirv emit to account for non-32-bit ints --- source/slang/slang-emit-spirv.cpp | 56 +++++++++++-------- .../bitfield/bitfield-extract-i64.slang | 4 +- .../bitfield/bitfield-insert-i64.slang | 6 +- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 2bde48d45e..0779516147 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -5600,46 +5600,54 @@ struct SPIRVEmitContext return emitInst(parent, inst, SpvOpConvertUToPtr, inst->getFullType(), kResultID, inst->getOperand(0)); } + bool tryGetIntInfo(IRType* elementType, bool &isSigned, int &bitWidth) + { + Slang::IROp type = elementType->getOp(); + if (!(type >= kIROp_Int8Type && type <= kIROp_UInt64Type)) return false; + isSigned = (type >= kIROp_Int8Type && type <= kIROp_Int64Type); + + Slang::IROp stype = (isSigned) ? type : Slang::IROp(type - 4); + bitWidth = 8 << (stype - kIROp_Int8Type); + return true; + } + SpvInst* emitBitfieldExtract(SpvInstParent* parent, IRInst* inst) { auto dataType = inst->getDataType(); IRVectorType* vectorType = as(dataType); + Slang::IRType* elementType = dataType; if (vectorType) + elementType = vectorType->getElementType(); + + bool isSigned; + int bitWidth; + if (!tryGetIntInfo(elementType, isSigned, bitWidth)) { - dataType = vectorType->getElementType(); + SLANG_UNEXPECTED("non-integer element type given to bitfieldExtract in SPIR-V emit"); + UNREACHABLE_RETURN(nullptr); } - switch (dataType->getOp()) - { - case kIROp_UIntType: - return emitInst(parent, inst, SpvOpBitFieldUExtract, inst->getFullType(), kResultID, - inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); - case kIROp_IntType: - return emitInst(parent, inst, SpvOpBitFieldSExtract, inst->getFullType(), kResultID, - inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); - default: - SLANG_UNEXPECTED("type given to bitfieldExtract in SPIR-V emit"); - } - UNREACHABLE_RETURN(nullptr); + SpvOp opcode = isSigned ? SpvOpBitFieldSExtract : SpvOpBitFieldUExtract; + return emitInst(parent, inst, opcode, inst->getFullType(), kResultID, + inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); } SpvInst* emitBitfieldInsert(SpvInstParent* parent, IRInst* inst) { auto dataType = inst->getDataType(); IRVectorType* vectorType = as(dataType); + Slang::IRType* elementType = dataType; if (vectorType) - { - dataType = vectorType->getElementType(); - } + elementType = vectorType->getElementType(); - switch (dataType->getOp()) + bool isSigned; + int bitWidth; + if (!tryGetIntInfo(elementType, isSigned, bitWidth)) { - case kIROp_UIntType: - case kIROp_IntType: - return emitInst(parent, inst, SpvOpBitFieldInsert, inst->getFullType(), kResultID, - inst->getOperand(0), inst->getOperand(1), inst->getOperand(2), inst->getOperand(3)); - default: - SLANG_UNEXPECTED("type given to bitfieldInsert in SPIR-V emit"); + SLANG_UNEXPECTED("non-integer element type given to bitfieldInsert in SPIR-V emit"); + UNREACHABLE_RETURN(nullptr); } - UNREACHABLE_RETURN(nullptr); + + return emitInst(parent, inst, SpvOpBitFieldInsert, inst->getFullType(), kResultID, + inst->getOperand(0), inst->getOperand(1), inst->getOperand(2), inst->getOperand(3)); } template diff --git a/tests/language-feature/bitfield/bitfield-extract-i64.slang b/tests/language-feature/bitfield/bitfield-extract-i64.slang index 2b8378c2f0..cb87097f80 100644 --- a/tests/language-feature/bitfield/bitfield-extract-i64.slang +++ b/tests/language-feature/bitfield/bitfield-extract-i64.slang @@ -67,8 +67,8 @@ void computeMain() outputBuffer[11] = bitfieldExtract(0b1010111ull, 3, 4); // 0b1010 -> 0b00000000000000000000000000001010 // Component-wise extraction - int64_t4 val4 = int64_t4(0x123456789abcdef0ll, 0x9abcdef012345678ll, 0x87654321fedcba98ll, 0xfedcba9876543210ll); - int64_t4 ext4 = bitfieldExtract(val4, 40, 8); + vector val4 = vector(0x123456789abcdef0ll, 0x9abcdef012345678ll, 0x87654321fedcba98ll, 0xfedcba9876543210ll); + vector ext4 = bitfieldExtract(val4, 40, 8); outputBuffer[12] = ext4.x; outputBuffer[13] = ext4.y; outputBuffer[14] = ext4.z; diff --git a/tests/language-feature/bitfield/bitfield-insert-i64.slang b/tests/language-feature/bitfield/bitfield-insert-i64.slang index 2f8942786f..b622356ed1 100644 --- a/tests/language-feature/bitfield/bitfield-insert-i64.slang +++ b/tests/language-feature/bitfield/bitfield-insert-i64.slang @@ -46,9 +46,9 @@ void computeMain() outputBuffer[5] = bitfieldInsert(base, insert, 40, 4); // 0xF000000000 -> 10477124133360 // Test with a vector - uint64_t4 base4 = uint64_t4(base, base, base, base); - uint64_t4 insert4 = uint64_t4(insert, insert, insert, insert); - uint64_t4 output4 = bitfieldInsert(base4, insert4, 4, 40); + vector base4 = vector(base, base, base, base); + vector insert4 = vector(insert, insert, insert, insert); + vector output4 = bitfieldInsert(base4, insert4, 4, 40); outputBuffer[6] = output4.x; outputBuffer[7] = output4.y; outputBuffer[8] = output4.z; From 4cd73c9c90ce570c764cb9b07960eb5c315b670c Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Tue, 10 Sep 2024 13:15:51 -0700 Subject: [PATCH 10/17] some refactoring for metal --- source/slang/slang-emit-c-like.cpp | 101 +++++++++--------- .../bitfield/bitfield-extract-i32.slang | 2 +- .../bitfield/bitfield-extract-i64.slang | 2 +- .../bitfield/bitfield-insert-i32.slang | 2 +- .../bitfield/bitfield-insert-i64.slang | 2 +- 5 files changed, 54 insertions(+), 55 deletions(-) diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 3361ec0574..4a6ba88520 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3715,6 +3715,17 @@ void CLikeSourceEmitter::emitVecNOrScalar(IRVectorType* vectorType, std::functio m_writer->emitRawText(std::to_string(N).c_str()); } + // Special handling required for Metal target + else if (isMetalTarget(getTargetReq())) + { + m_writer->emit("vec<"); + emitType(elementType); + m_writer->emit(", "); + m_writer->emit(N); + m_writer->emit(">"); + } + + // In other languages, we can output the Slang vector type directly else { emitType(vectorType); } @@ -3760,6 +3771,8 @@ void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "non-integer element type given to bitfieldExtract"); return; } + + String one = bitWidth <= 32 ? "1u" : "1ull"; // Emit open paren and type cast for later sign extension if (isSigned) @@ -3777,10 +3790,9 @@ void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) }); m_writer->emit(")&("); emitVecNOrScalar(vectorType, [&]() { - if (bitWidth <= 32) m_writer->emit("((1u<<"); - else m_writer->emit("((1ull<<"); + m_writer->emit("((" + one + "<<"); emitOperand(bts, getInfo(EmitOp::General)); - m_writer->emit(")-1)"); + m_writer->emit(")-" + one + ")"); }); m_writer->emit("))"); @@ -3836,58 +3848,45 @@ void CLikeSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) return; } - m_writer->emit("("); + String one = bitWidth <= 32 ? "1u" : "1ull"; + + m_writer->emit("(("); + + // emit clearedBase := uint(bse & ~(((1u<emit("&"); + emitVecNOrScalar(vectorType, [&]() { - // emit clearedBase := uint(base & clearMask) - m_writer->emit("("); - { - // emit base - emitOperand(bse, getInfo(EmitOp::General)); - m_writer->emit("&"); - - // emit clearMask := ~(((1u<emit("~(((1u<<"); - else m_writer->emit("~(((1ull<<"); - emitOperand(bts, getInfo(EmitOp::General)); - if (bitWidth <= 32) m_writer->emit(")-1u)<<"); - else m_writer->emit(")-1ull)<<"); - emitOperand(off, getInfo(EmitOp::General)); - m_writer->emit(")"); - }); - } + m_writer->emit("~(((" + one + "<<"); + emitOperand(bts, getInfo(EmitOp::General)); + m_writer->emit(")-" + one + ")<<"); + emitOperand(off, getInfo(EmitOp::General)); m_writer->emit(")"); + }); + + + // bitwise or clearedBase with maskedInsert + m_writer->emit(")|("); - // bitwise or clearedBase with maskedInsert - m_writer->emit("|"); - - // Emit maskedInsert := ((insert & ((1u << bits) - 1u)) << offset); - m_writer->emit("("); - { - // Emit mask := (insert & ((1u << bits) - 1u)) - m_writer->emit("("); - emitOperand(ins, getInfo(EmitOp::General)); - m_writer->emit("&"); - emitVecNOrScalar(vectorType, [&](){ - if (bitWidth <= 32) m_writer->emit("(1u<<"); - else m_writer->emit("(1ull<<"); - emitOperand(bts, getInfo(EmitOp::General)); - if (bitWidth <= 32) m_writer->emit(")-1u"); - else m_writer->emit(")-1ull"); - }); - m_writer->emit(")"); - - // Emit shift := << offset - m_writer->emit("<<"); - - emitVecNOrScalar(vectorType, [&](){ - emitOperand(off, getInfo(EmitOp::General)); - }); - } - m_writer->emit(")"); - } + // Emit maskedInsert := ((insert & ((1u << bits) - 1u)) << offset); + + // - first emit mask := (insert & ((1u << bits) - 1u)) + m_writer->emit("("); + emitOperand(ins, getInfo(EmitOp::General)); + m_writer->emit("&"); + emitVecNOrScalar(vectorType, [&](){ + m_writer->emit("(" + one + "<<"); + emitOperand(bts, getInfo(EmitOp::General)); + m_writer->emit(")-" + one); + }); m_writer->emit(")"); + + // then emit shift := << offset + m_writer->emit("<<"); + emitVecNOrScalar(vectorType, [&](){ + emitOperand(off, getInfo(EmitOp::General)); + }); + m_writer->emit("))"); } void CLikeSourceEmitter::emitStruct(IRStructType* structType) diff --git a/tests/language-feature/bitfield/bitfield-extract-i32.slang b/tests/language-feature/bitfield/bitfield-extract-i32.slang index 8bbb9e3552..9a8d2fec1a 100644 --- a/tests/language-feature/bitfield/bitfield-extract-i32.slang +++ b/tests/language-feature/bitfield/bitfield-extract-i32.slang @@ -1,5 +1,5 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda diff --git a/tests/language-feature/bitfield/bitfield-extract-i64.slang b/tests/language-feature/bitfield/bitfield-extract-i64.slang index cb87097f80..ba57b51539 100644 --- a/tests/language-feature/bitfield/bitfield-extract-i64.slang +++ b/tests/language-feature/bitfield/bitfield-extract-i64.slang @@ -1,5 +1,5 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda diff --git a/tests/language-feature/bitfield/bitfield-insert-i32.slang b/tests/language-feature/bitfield/bitfield-insert-i32.slang index dccac43cb0..7d4ceac050 100644 --- a/tests/language-feature/bitfield/bitfield-insert-i32.slang +++ b/tests/language-feature/bitfield/bitfield-insert-i32.slang @@ -1,5 +1,5 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda diff --git a/tests/language-feature/bitfield/bitfield-insert-i64.slang b/tests/language-feature/bitfield/bitfield-insert-i64.slang index b622356ed1..712b45026c 100644 --- a/tests/language-feature/bitfield/bitfield-insert-i64.slang +++ b/tests/language-feature/bitfield/bitfield-insert-i64.slang @@ -1,5 +1,5 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda From 164a01b2ece1a5ddaef79eb32ccf3baab722195c Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Fri, 13 Sep 2024 10:53:52 -0700 Subject: [PATCH 11/17] making sign extension more robust to order ops which can vary between targets --- source/slang/slang-emit-c-like.cpp | 23 +++++-- source/slang/slang-emit-spirv.cpp | 68 +++++++++++-------- .../bitfield/bitfield-extract-i32.slang | 2 +- .../bitfield/bitfield-extract-i64.slang | 2 +- .../bitfield/bitfield-insert-i32.slang | 2 +- .../bitfield/bitfield-insert-i64.slang | 2 +- 6 files changed, 64 insertions(+), 35 deletions(-) diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 4a6ba88520..16d68f6d21 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3772,13 +3772,21 @@ void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) return; } - String one = bitWidth <= 32 ? "1u" : "1ull"; + String one; + switch(bitWidth) { + case 8: one = "uint8_t(1)"; break; + case 16: one = "uint16_t(1)"; break; + case 32: one = "uint32_t(1)"; break; + case 64: one = "uint64_t(1)"; break; + default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unexpected bit width"); + } // Emit open paren and type cast for later sign extension if (isSigned) { m_writer->emit("("); emitType(inst->getDataType()); + m_writer->emit("("); } // Emit bitfield extraction ((val>>off)&((1u<emit("))"); // Emit sign extension logic - // (bitfield<<(numBits-bts)>>(numBits-bts)) + // (type(bitfield<<(numBits-bts))>>(numBits-bts)) // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ if (isSigned) { @@ -3810,7 +3818,7 @@ void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) emitOperand(bts, getInfo(EmitOp::General)); m_writer->emit(")"); }); - m_writer->emit(">>"); + m_writer->emit(")>>"); emitVecNOrScalar(vectorType, [&]() { m_writer->emit("("); @@ -3848,7 +3856,14 @@ void CLikeSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) return; } - String one = bitWidth <= 32 ? "1u" : "1ull"; + String one; + switch(bitWidth) { + case 8: one = "uint8_t(1)"; break; + case 16: one = "uint16_t(1)"; break; + case 32: one = "uint32_t(1)"; break; + case 64: one = "uint64_t(1)"; break; + default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unexpected bit width"); + } m_writer->emit("(("); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 0779516147..7f2e0a73b1 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -5600,17 +5600,6 @@ struct SPIRVEmitContext return emitInst(parent, inst, SpvOpConvertUToPtr, inst->getFullType(), kResultID, inst->getOperand(0)); } - bool tryGetIntInfo(IRType* elementType, bool &isSigned, int &bitWidth) - { - Slang::IROp type = elementType->getOp(); - if (!(type >= kIROp_Int8Type && type <= kIROp_UInt64Type)) return false; - isSigned = (type >= kIROp_Int8Type && type <= kIROp_Int64Type); - - Slang::IROp stype = (isSigned) ? type : Slang::IROp(type - 4); - bitWidth = 8 << (stype - kIROp_Int8Type); - return true; - } - SpvInst* emitBitfieldExtract(SpvInstParent* parent, IRInst* inst) { auto dataType = inst->getDataType(); IRVectorType* vectorType = as(dataType); @@ -5618,17 +5607,41 @@ struct SPIRVEmitContext if (vectorType) elementType = vectorType->getElementType(); - bool isSigned; - int bitWidth; - if (!tryGetIntInfo(elementType, isSigned, bitWidth)) - { - SLANG_UNEXPECTED("non-integer element type given to bitfieldExtract in SPIR-V emit"); - UNREACHABLE_RETURN(nullptr); - } + const IntInfo i = getIntTypeInfo(elementType); - SpvOp opcode = isSigned ? SpvOpBitFieldSExtract : SpvOpBitFieldUExtract; + SpvOp opcode = i.isSigned ? SpvOpBitFieldSExtract : SpvOpBitFieldUExtract; return emitInst(parent, inst, opcode, inst->getFullType(), kResultID, - inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); + inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); + + // SpvOp opcastcode = i.isSigned ? SpvOpSConvert : SpvOpUConvert; + + // IRBuilder builder(inst); + // builder.setInsertBefore(inst); + // Slang::IRType* i32Type = i.isSigned ? builder.getIntType() : builder.getUIntType(); + // Slang::IRType* toTypeV = i32Type; + // Slang::IRType* fromTypeV = dataType; + // if (vectorType) { + // toTypeV = builder.getVectorType(i32Type, vectorType->getElementCount()); + // } + + + + // if (i.width == 32) { + // // For 32-bit types, we can just emit the instruction directly. + + // } + // else if (i.width < 32) { + // // For smaller types, we need to promote to a 32-bit type, then go back. + // Slang::IRInst * i32Val = builder.emitCast(toTypeV, inst->getOperand(0)); + // emitLocalInst(parent, i32Val); + // Slang::IRInst * result = builder.emitBitfieldExtract(toTypeV, i32Val, inst->getOperand(1), inst->getOperand(2)); + // Slang::SpvInst * resultSpv = emitLocalInst(parent, result); + // Slang::SpvInst * back = emitInst(parent, inst, opcastcode, fromTypeV, kResultID, resultSpv); + // return back; + // } + // else { + // SLANG_UNIMPLEMENTED_X("64-bit bitfieldExtract in SPIR-V emit"); + // } } SpvInst* emitBitfieldInsert(SpvInstParent* parent, IRInst* inst) { @@ -5638,13 +5651,14 @@ struct SPIRVEmitContext if (vectorType) elementType = vectorType->getElementType(); - bool isSigned; - int bitWidth; - if (!tryGetIntInfo(elementType, isSigned, bitWidth)) - { - SLANG_UNEXPECTED("non-integer element type given to bitfieldInsert in SPIR-V emit"); - UNREACHABLE_RETURN(nullptr); - } + const IntInfo i = getIntTypeInfo(elementType); + + if (i.width == 64) + requireSPIRVCapability(SpvCapabilityInt64); + if (i.width == 16) + requireSPIRVCapability(SpvCapabilityInt16); + if (i.width == 8) + requireSPIRVCapability(SpvCapabilityInt8); return emitInst(parent, inst, SpvOpBitFieldInsert, inst->getFullType(), kResultID, inst->getOperand(0), inst->getOperand(1), inst->getOperand(2), inst->getOperand(3)); diff --git a/tests/language-feature/bitfield/bitfield-extract-i32.slang b/tests/language-feature/bitfield/bitfield-extract-i32.slang index 9a8d2fec1a..b4a5a47195 100644 --- a/tests/language-feature/bitfield/bitfield-extract-i32.slang +++ b/tests/language-feature/bitfield/bitfield-extract-i32.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu diff --git a/tests/language-feature/bitfield/bitfield-extract-i64.slang b/tests/language-feature/bitfield/bitfield-extract-i64.slang index ba57b51539..f071d10ddf 100644 --- a/tests/language-feature/bitfield/bitfield-extract-i64.slang +++ b/tests/language-feature/bitfield/bitfield-extract-i64.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu diff --git a/tests/language-feature/bitfield/bitfield-insert-i32.slang b/tests/language-feature/bitfield/bitfield-insert-i32.slang index 7d4ceac050..22249e3fea 100644 --- a/tests/language-feature/bitfield/bitfield-insert-i32.slang +++ b/tests/language-feature/bitfield/bitfield-insert-i32.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu diff --git a/tests/language-feature/bitfield/bitfield-insert-i64.slang b/tests/language-feature/bitfield/bitfield-insert-i64.slang index 712b45026c..214aaae00e 100644 --- a/tests/language-feature/bitfield/bitfield-insert-i64.slang +++ b/tests/language-feature/bitfield/bitfield-insert-i64.slang @@ -1,4 +1,4 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu From fe183e224b03565055ff28dc37cfbcc10afcb015 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Sun, 15 Sep 2024 11:26:45 -0700 Subject: [PATCH 12/17] updating slang emit metal to try to correct emitting 64-bit vector types --- source/slang/slang-emit-metal.cpp | 20 +++++++++++++++---- source/slang/slang-emit-metal.h | 2 ++ source/slang/slang-emit-spirv.cpp | 33 +++---------------------------- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/source/slang/slang-emit-metal.cpp b/source/slang/slang-emit-metal.cpp index a0fe220e58..f99e37a2c6 100644 --- a/source/slang/slang-emit-metal.cpp +++ b/source/slang/slang-emit-metal.cpp @@ -538,7 +538,8 @@ bool MetalSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inO void MetalSourceEmitter::emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) { - emitSimpleTypeImpl(elementType); + // NM: Passing count here, as Metal 64-bit vector type names do not match their scalar equivalents. + emitSimpleTypeKnowingCount(elementType, elementCount); switch (elementType->getOp()) { @@ -656,7 +657,7 @@ void MetalSourceEmitter::emitParamTypeImpl(IRType* type, String const& name) emitType(type, name); } -void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type) +void MetalSourceEmitter::emitSimpleTypeKnowingCount(IRType* type, IRIntegerValue elementCount) { switch (type->getOp()) { @@ -682,10 +683,16 @@ void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type) m_writer->emit("ushort"); return; case kIROp_IntPtrType: - m_writer->emit("int64_t"); + // NM: note, "long" is only type that works for i64 vec + m_writer->emit("long"); return; case kIROp_UIntPtrType: - m_writer->emit("uint64_t"); + // NM: note, "ulong" is only type that works for i64 vec, but can't be used for scalars. + // (See metal specification pg 26) + if (elementCount > 1) + m_writer->emit("ulong"); + else + m_writer->emit("uint64_t"); return; case kIROp_StructType: m_writer->emit(getName(type)); @@ -887,6 +894,11 @@ void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type) } } +void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type) +{ + emitSimpleTypeKnowingCount(type, 1); +} + void MetalSourceEmitter::_emitType(IRType* type, DeclaratorInfo* declarator) { switch (type->getOp()) diff --git a/source/slang/slang-emit-metal.h b/source/slang/slang-emit-metal.h index 67aa0d506e..66e3523978 100644 --- a/source/slang/slang-emit-metal.h +++ b/source/slang/slang-emit-metal.h @@ -39,6 +39,8 @@ class MetalSourceEmitter : public CLikeSourceEmitter virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE; virtual void emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* decoration) SLANG_OVERRIDE; + void emitSimpleTypeKnowingCount(IRType* type, IRIntegerValue elementCount); + virtual void emitMeshShaderModifiersImpl(IRInst* varInst) SLANG_OVERRIDE; virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE; virtual void emitParamTypeImpl(IRType* type, String const& name) SLANG_OVERRIDE; diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 7f2e0a73b1..e2e501adf8 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -5609,39 +5609,12 @@ struct SPIRVEmitContext const IntInfo i = getIntTypeInfo(elementType); + // NM: technically, using bitfield intrinsics for anything non-32-bit goes against + // VK specification: VUID-StandaloneSpirv-Base-04781. However, it works on at least + // NVIDIA HW. SpvOp opcode = i.isSigned ? SpvOpBitFieldSExtract : SpvOpBitFieldUExtract; return emitInst(parent, inst, opcode, inst->getFullType(), kResultID, inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); - - // SpvOp opcastcode = i.isSigned ? SpvOpSConvert : SpvOpUConvert; - - // IRBuilder builder(inst); - // builder.setInsertBefore(inst); - // Slang::IRType* i32Type = i.isSigned ? builder.getIntType() : builder.getUIntType(); - // Slang::IRType* toTypeV = i32Type; - // Slang::IRType* fromTypeV = dataType; - // if (vectorType) { - // toTypeV = builder.getVectorType(i32Type, vectorType->getElementCount()); - // } - - - - // if (i.width == 32) { - // // For 32-bit types, we can just emit the instruction directly. - - // } - // else if (i.width < 32) { - // // For smaller types, we need to promote to a 32-bit type, then go back. - // Slang::IRInst * i32Val = builder.emitCast(toTypeV, inst->getOperand(0)); - // emitLocalInst(parent, i32Val); - // Slang::IRInst * result = builder.emitBitfieldExtract(toTypeV, i32Val, inst->getOperand(1), inst->getOperand(2)); - // Slang::SpvInst * resultSpv = emitLocalInst(parent, result); - // Slang::SpvInst * back = emitInst(parent, inst, opcastcode, fromTypeV, kResultID, resultSpv); - // return back; - // } - // else { - // SLANG_UNIMPLEMENTED_X("64-bit bitfieldExtract in SPIR-V emit"); - // } } SpvInst* emitBitfieldInsert(SpvInstParent* parent, IRInst* inst) { From 8d2a47e0178679c75e9addbefbdc20dc3cdb951a Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Sun, 15 Sep 2024 11:53:08 -0700 Subject: [PATCH 13/17] fixing missed switch cases --- source/slang/slang-emit-metal.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/slang/slang-emit-metal.cpp b/source/slang/slang-emit-metal.cpp index f99e37a2c6..2ba41da1ae 100644 --- a/source/slang/slang-emit-metal.cpp +++ b/source/slang/slang-emit-metal.cpp @@ -665,10 +665,8 @@ void MetalSourceEmitter::emitSimpleTypeKnowingCount(IRType* type, IRIntegerValue case kIROp_BoolType: case kIROp_Int8Type: case kIROp_IntType: - case kIROp_Int64Type: case kIROp_UInt8Type: case kIROp_UIntType: - case kIROp_UInt64Type: case kIROp_FloatType: case kIROp_DoubleType: case kIROp_HalfType: @@ -682,10 +680,12 @@ void MetalSourceEmitter::emitSimpleTypeKnowingCount(IRType* type, IRIntegerValue case kIROp_UInt16Type: m_writer->emit("ushort"); return; + case kIROp_Int64Type: case kIROp_IntPtrType: // NM: note, "long" is only type that works for i64 vec m_writer->emit("long"); return; + case kIROp_UInt64Type: case kIROp_UIntPtrType: // NM: note, "ulong" is only type that works for i64 vec, but can't be used for scalars. // (See metal specification pg 26) From 7eb6b20dd1c4605c4ac98a5327d78e82519dac97 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Sun, 15 Sep 2024 12:02:57 -0700 Subject: [PATCH 14/17] refactoring tests --- .../bitfield/bitfield-extract-i32.slang | 60 ------- .../bitfield/bitfield-extract-i64.slang | 76 --------- .../bitfield/bitfield-extract.slang | 159 ++++++++++++++++++ .../bitfield/bitfield-insert-i32.slang | 47 ------ .../bitfield/bitfield-insert-i64.slang | 56 ------ .../bitfield/bitfield-insert.slang | 100 +++++++++++ 6 files changed, 259 insertions(+), 239 deletions(-) delete mode 100644 tests/language-feature/bitfield/bitfield-extract-i32.slang delete mode 100644 tests/language-feature/bitfield/bitfield-extract-i64.slang create mode 100644 tests/language-feature/bitfield/bitfield-extract.slang delete mode 100644 tests/language-feature/bitfield/bitfield-insert-i32.slang delete mode 100644 tests/language-feature/bitfield/bitfield-insert-i64.slang create mode 100644 tests/language-feature/bitfield/bitfield-insert.slang diff --git a/tests/language-feature/bitfield/bitfield-extract-i32.slang b/tests/language-feature/bitfield/bitfield-extract-i32.slang deleted file mode 100644 index b4a5a47195..0000000000 --- a/tests/language-feature/bitfield/bitfield-extract-i32.slang +++ /dev/null @@ -1,60 +0,0 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda - -// CHECK: 1 -// CHECK-NEXT: 2 -// CHECK-NEXT: 3 -// CHECK-NEXT: 4 -// CHECK-NEXT: 5 -// CHECK-NEXT: 6 -// CHECK-NEXT: 7 -// CHECK-NEXT: 8 -// CHECK-NEXT: 21 -// CHECK-NEXT: 7A -// CHECK-NEXT: FFFFFFFA -// CHECK-NEXT: A -// CHECK-NEXT: 67 -// CHECK-NEXT: FFFFFFEF -// CHECK-NEXT: 32 -// CHECK-NEXT: FFFFFFA9 - -//TEST_INPUT:ubuffer(data=[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1], stride=4):out,name=outputBuffer -RWStructuredBuffer outputBuffer; - -[numthreads(1, 1, 1)] -void computeMain() -{ - // Simple hex extraction to test, varying the offset. - uint value = 0x87654321; - outputBuffer[0] = bitfieldExtract(value, 4 * 0, 4); - outputBuffer[1] = bitfieldExtract(value, 4 * 1, 4); - outputBuffer[2] = bitfieldExtract(value, 4 * 2, 4); - outputBuffer[3] = bitfieldExtract(value, 4 * 3, 4); - outputBuffer[4] = bitfieldExtract(value, 4 * 4, 4); - outputBuffer[5] = bitfieldExtract(value, 4 * 5, 4); - outputBuffer[6] = bitfieldExtract(value, 4 * 6, 4); - outputBuffer[7] = bitfieldExtract(value, 4 * 7, 4); - - // Now varying the bit length - value = 0b00111011111011110001111010100001; - outputBuffer[8] = bitfieldExtract(value, 0, 6); - outputBuffer[9] = bitfieldExtract(value, 6, 8); - - // Sign extension case - // - For unsigned data types, the most significant bits of the result will be set to zero. - // - For signed data types, the most significant bits will be set to the value of bit offset + base - 1 - // (i.e., it is sign extended to the width of the return type). - outputBuffer[10] = bitfieldExtract(0b1010111, 3, 4); // 0b1010 -> 0b11111111111111111111111111111010 - outputBuffer[11] = bitfieldExtract(0b1010111u, 3, 4); // 0b1111 -> 0b00000000000000000000000000001010 - - // Component-wise extraction - int4 val4 = int4(0x12345678, 0x9abcdef0, 0x87654321, 0xfedcba98); - int4 ext4 = bitfieldExtract(val4, 4, 8); - outputBuffer[12] = ext4.x; - outputBuffer[13] = ext4.y; - outputBuffer[14] = ext4.z; - outputBuffer[15] = ext4.w; -} diff --git a/tests/language-feature/bitfield/bitfield-extract-i64.slang b/tests/language-feature/bitfield/bitfield-extract-i64.slang deleted file mode 100644 index f071d10ddf..0000000000 --- a/tests/language-feature/bitfield/bitfield-extract-i64.slang +++ /dev/null @@ -1,76 +0,0 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda - -// CHECK: 0 -// CHECK-NEXT: 0 -// CHECK-NEXT: 2 -// CHECK-NEXT: 0 -// CHECK-NEXT: 4 -// CHECK-NEXT: 0 -// CHECK-NEXT: 6 -// CHECK-NEXT: 0 -// CHECK-NEXT: 8 -// CHECK-NEXT: 0 -// CHECK-NEXT: D -// CHECK-NEXT: 0 -// CHECK-NEXT: B -// CHECK-NEXT: 0 -// CHECK-NEXT: A -// CHECK-NEXT: 0 -// CHECK-NEXT: 89ABCDEF -// CHECK-NEXT: 67 -// CHECK-NEXT: A12345 -// CHECK-NEXT: 0 -// CHECK-NEXT: FFFFFFFA -// CHECK-NEXT: FFFFFFFF -// CHECK-NEXT: A -// CHECK-NEXT: 0 -// CHECK-NEXT: 56 -// CHECK-NEXT: 0 -// CHECK-NEXT: FFFFFFDE -// CHECK-NEXT: FFFFFFFF -// CHECK-NEXT: 43 -// CHECK-NEXT: 0 -// CHECK-NEXT: FFFFFFBA -// CHECK-NEXT: FFFFFFFF - -//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer -RWStructuredBuffer outputBuffer; - -[numthreads(1, 1, 1)] -void computeMain() -{ - // Simple hex extraction to test, varying the offset. - uint64_t value = 0xABCDEF9876543210ull; - outputBuffer[0] = bitfieldExtract(value, 4 * 0, 4); - outputBuffer[1] = bitfieldExtract(value, 4 * 2, 4); - outputBuffer[2] = bitfieldExtract(value, 4 * 4, 4); - outputBuffer[3] = bitfieldExtract(value, 4 * 6, 4); - outputBuffer[4] = bitfieldExtract(value, 4 * 8, 4); - outputBuffer[5] = bitfieldExtract(value, 4 * 12, 4); - outputBuffer[6] = bitfieldExtract(value, 4 * 14, 4); - outputBuffer[7] = bitfieldExtract(value, 4 * 15, 4); - - // Now varying the bit length - value = 0xA123456789ABCDEFull; - outputBuffer[8] = bitfieldExtract(value, 0, 40); // 0x6789ABCDEF - outputBuffer[9] = bitfieldExtract(value, 40, 24); // 0xA12345 - - // Sign extension case - // - For unsigned data types, the most significant bits of the result will be set to zero. - // - For signed data types, the most significant bits will be set to the value of bit offset + base - 1 - // (i.e., it is sign extended to the width of the return type). - outputBuffer[10] = bitfieldExtract(0b1010111ll, 3, 4); // 0b1010 -> 0b11111111111111111111111111111010 - outputBuffer[11] = bitfieldExtract(0b1010111ull, 3, 4); // 0b1010 -> 0b00000000000000000000000000001010 - - // Component-wise extraction - vector val4 = vector(0x123456789abcdef0ll, 0x9abcdef012345678ll, 0x87654321fedcba98ll, 0xfedcba9876543210ll); - vector ext4 = bitfieldExtract(val4, 40, 8); - outputBuffer[12] = ext4.x; - outputBuffer[13] = ext4.y; - outputBuffer[14] = ext4.z; - outputBuffer[15] = ext4.w; -} diff --git a/tests/language-feature/bitfield/bitfield-extract.slang b/tests/language-feature/bitfield/bitfield-extract.slang new file mode 100644 index 0000000000..06896157f6 --- /dev/null +++ b/tests/language-feature/bitfield/bitfield-extract.slang @@ -0,0 +1,159 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda + +// CHECK: 1 +// CHECK-NEXT: 2 +// CHECK-NEXT: 3 +// CHECK-NEXT: 4 +// CHECK-NEXT: 35 +// CHECK-NEXT: BE +// CHECK-NEXT: FFFFFFFA +// CHECK-NEXT: A +// CHECK-NEXT: 23 +// CHECK-NEXT: FFFFFFAB +// CHECK-NEXT: 76 +// CHECK-NEXT: FFFFFFED + +// CHECK-NEXT: 1 +// CHECK-NEXT: 2 +// CHECK-NEXT: 3 +// CHECK-NEXT: 4 +// CHECK-NEXT: 5 +// CHECK-NEXT: 6 +// CHECK-NEXT: 7 +// CHECK-NEXT: 8 +// CHECK-NEXT: 21 +// CHECK-NEXT: 7A +// CHECK-NEXT: FFFFFFFA +// CHECK-NEXT: A +// CHECK-NEXT: 67 +// CHECK-NEXT: FFFFFFEF +// CHECK-NEXT: 32 +// CHECK-NEXT: FFFFFFA9 + +// CHECK-NEXT: 7654321A +// CHECK-NEXT: FEDCBA98 +// CHECK-NEXT: 76543210 +// CHECK-NEXT: FEDCBA9A +// CHECK-NEXT: 76543210 +// CHECK-NEXT: FEDABA98 +// CHECK-NEXT: 76543210 +// CHECK-NEXT: AEDCBA98 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 0 +// CHECK-NEXT: F00 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 + +//TEST_INPUT:ubuffer(data=[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1], stride=4):out,name=i16Buffer +RWStructuredBuffer i16Buffer; + +//TEST_INPUT:ubuffer(data=[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1], stride=4):out,name=i32Buffer +RWStructuredBuffer i32Buffer; + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=i64Buffer +RWStructuredBuffer i64Buffer; + +[numthreads(1, 1, 1)] +void computeMain() +{ + // 16-bit tests + { + // Simple hex extraction to test, varying the offset. + uint16_t value = 0x4321; + i16Buffer[0] = bitfieldExtract(value, 4 * 0, 4); + i16Buffer[1] = bitfieldExtract(value, 4 * 1, 4); + i16Buffer[2] = bitfieldExtract(value, 4 * 2, 4); + i16Buffer[3] = bitfieldExtract(value, 4 * 3, 4); + + // Now varying the bit length + value = 0b001110111110110101; + i16Buffer[4] = bitfieldExtract(value, 0, 6); + i16Buffer[5] = bitfieldExtract(value, 6, 8); + + // Sign extension case + // - For unsigned data types, the most significant bits of the result will be set to zero. + // - For signed data types, the most significant bits will be set to the value of bit offset + base - 1 + // (i.e., it is sign extended to the width of the return type). + i16Buffer[6] = bitfieldExtract(int16_t(0b1010111), 3, 4); // 0b1010 -> 0b1111111111111010 + i16Buffer[7] = bitfieldExtract(uint16_t(0b1010111u), 3, 4); // 0b1111 -> 0b0000000000001010 + + // // Component-wise extraction + vector val4 = vector(0x1234, 0x9abc, 0x8765, 0xfedc); + vector ext4 = bitfieldExtract(val4, 4, 8); + i16Buffer[8] = ext4.x; + i16Buffer[9] = ext4.y; + i16Buffer[10] = ext4.z; + i16Buffer[11] = ext4.w; + } + + // 32-bit tests + { + // Simple hex extraction to test, varying the offset. + uint value = 0x87654321; + i32Buffer[0] = bitfieldExtract(value, 4 * 0, 4); + i32Buffer[1] = bitfieldExtract(value, 4 * 1, 4); + i32Buffer[2] = bitfieldExtract(value, 4 * 2, 4); + i32Buffer[3] = bitfieldExtract(value, 4 * 3, 4); + i32Buffer[4] = bitfieldExtract(value, 4 * 4, 4); + i32Buffer[5] = bitfieldExtract(value, 4 * 5, 4); + i32Buffer[6] = bitfieldExtract(value, 4 * 6, 4); + i32Buffer[7] = bitfieldExtract(value, 4 * 7, 4); + + // Now varying the bit length + value = 0b00111011111011110001111010100001; + i32Buffer[8] = bitfieldExtract(value, 0, 6); + i32Buffer[9] = bitfieldExtract(value, 6, 8); + + // Sign extension case + // - For unsigned data types, the most significant bits of the result will be set to zero. + // - For signed data types, the most significant bits will be set to the value of bit offset + base - 1 + // (i.e., it is sign extended to the width of the return type). + i32Buffer[10] = bitfieldExtract(0b1010111, 3, 4); // 0b1010 -> 0b11111111111111111111111111111010 + i32Buffer[11] = bitfieldExtract(0b1010111u, 3, 4); // 0b1111 -> 0b00000000000000000000000000001010 + + // Component-wise extraction + int4 val4 = int4(0x12345678, 0x9abcdef0, 0x87654321, 0xfedcba98); + int4 ext4 = bitfieldExtract(val4, 4, 8); + i32Buffer[12] = ext4.x; + i32Buffer[13] = ext4.y; + i32Buffer[14] = ext4.z; + i32Buffer[15] = ext4.w; + } + + // 64-bit tests + { + // Simple hex insertion to test, varying the offset. + uint64_t base = 0xFEDCBA9876543210ull; + uint64_t insert = 0xAull; + i64Buffer[0] = bitfieldInsert(base, insert, 4 * 0, 4); // 0xFEDCBA987654321Aull -> 2271560495 + i64Buffer[1] = bitfieldInsert(base, insert, 4 * 8, 4); // 0xFEDCBA98A6543210ull -> 2271560689 + i64Buffer[2] = bitfieldInsert(base, insert, 4 * 12, 4); // 0xFEDCAA9876543210ull -> 2271563553 + i64Buffer[3] = bitfieldInsert(base, insert, 4 * 15, 4); // 0xAEDCBA9876543210ull -> 2271605537 + + // Test with varying bit length + base = 0; + insert = 0xFEDCBA987654321Full; + i64Buffer[4] = bitfieldInsert(base, insert, 4, 40); // 0xA987654321 -> 16492674416640 + i64Buffer[5] = bitfieldInsert(base, insert, 40, 4); // 0xF000000000 -> 10477124133360 + + // Test with a vector + vector base4 = vector(base, base, base, base); + vector insert4 = vector(insert, insert, insert, insert); + vector output4 = bitfieldInsert(base4, insert4, 4, 40); + i64Buffer[6] = output4.x; + i64Buffer[7] = output4.y; + i64Buffer[8] = output4.z; + i64Buffer[9] = output4.w; + } +} diff --git a/tests/language-feature/bitfield/bitfield-insert-i32.slang b/tests/language-feature/bitfield/bitfield-insert-i32.slang deleted file mode 100644 index 22249e3fea..0000000000 --- a/tests/language-feature/bitfield/bitfield-insert-i32.slang +++ /dev/null @@ -1,47 +0,0 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda - -// CHECK: 8765432F -// CHECK-NEXT: 876543F1 -// CHECK-NEXT: 87654F21 -// CHECK-NEXT: 8765F321 -// CHECK-NEXT: A8 -// CHECK-NEXT: 3FC0 -// CHECK-NEXT: 123456F8 -// CHECK-NEXT: 9ABCDE60 -// CHECK-NEXT: 87654331 -// CHECK-NEXT: FEDCBA68 - -//TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9], stride=4):out,name=outputBuffer -RWStructuredBuffer outputBuffer; - -[numthreads(1, 1, 1)] -void computeMain() -{ - // Simple hex insertion to test, varying the offset. - uint base = 0x87654321; - uint value = 0xABCDEF; - outputBuffer[0] = bitfieldInsert(base, value, 4 * 0, 4); // 0x8765432F -> 2271560495 - outputBuffer[1] = bitfieldInsert(base, value, 4 * 1, 4); // 0x876543F1 -> 2271560689 - outputBuffer[2] = bitfieldInsert(base, value, 4 * 2, 4); // 0x8765F321 -> 2271563553 - outputBuffer[3] = bitfieldInsert(base, value, 4 * 3, 4); // 0x87F54321 -> 2271605537 - - // Test with varying bit length - base = 0; - value = 0b101010; - outputBuffer[4] = bitfieldInsert(base, value, 2, 6); // 0b10101000 -> 1005526666 - value = 0b11111111; - outputBuffer[5] = bitfieldInsert(base, value, 6, 8); // 0b11111111000000 -> 1005519841 - - // Test with a vector - uint4 base4 = uint4(0x12345678, 0x9abcdef0, 0x87654321, 0xfedcba98); - uint4 value4 = uint4(0xABCDEF, 0x123456, 0x876543, 0x123456); - uint4 output4 = bitfieldInsert(base4, value4, 4, 4); - outputBuffer[6] = output4.x; - outputBuffer[7] = output4.y; - outputBuffer[8] = output4.z; - outputBuffer[9] = output4.w; -} diff --git a/tests/language-feature/bitfield/bitfield-insert-i64.slang b/tests/language-feature/bitfield/bitfield-insert-i64.slang deleted file mode 100644 index 214aaae00e..0000000000 --- a/tests/language-feature/bitfield/bitfield-insert-i64.slang +++ /dev/null @@ -1,56 +0,0 @@ -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda - -//CHECK: 7654321A -//CHECK-NEXT: FEDCBA98 -//CHECK-NEXT: 76543210 -//CHECK-NEXT: FEDCBA9A -//CHECK-NEXT: 76543210 -//CHECK-NEXT: FEDABA98 -//CHECK-NEXT: 76543210 -//CHECK-NEXT: AEDCBA98 -//CHECK-NEXT: 654321F0 -//CHECK-NEXT: 987 -//CHECK-NEXT: 0 -//CHECK-NEXT: F00 -//CHECK-NEXT: 654321F0 -//CHECK-NEXT: 987 -//CHECK-NEXT: 654321F0 -//CHECK-NEXT: 987 -//CHECK-NEXT: 654321F0 -//CHECK-NEXT: 987 -//CHECK-NEXT: 654321F0 -//CHECK-NEXT: 987 - -//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer -RWStructuredBuffer outputBuffer; - -[numthreads(1, 1, 1)] -void computeMain() -{ - // Simple hex insertion to test, varying the offset. - uint64_t base = 0xFEDCBA9876543210ull; - uint64_t insert = 0xAull; - outputBuffer[0] = bitfieldInsert(base, insert, 4 * 0, 4); // 0xFEDCBA987654321Aull -> 2271560495 - outputBuffer[1] = bitfieldInsert(base, insert, 4 * 8, 4); // 0xFEDCBA98A6543210ull -> 2271560689 - outputBuffer[2] = bitfieldInsert(base, insert, 4 * 12, 4); // 0xFEDCAA9876543210ull -> 2271563553 - outputBuffer[3] = bitfieldInsert(base, insert, 4 * 15, 4); // 0xAEDCBA9876543210ull -> 2271605537 - - // Test with varying bit length - base = 0; - insert = 0xFEDCBA987654321Full; - outputBuffer[4] = bitfieldInsert(base, insert, 4, 40); // 0xA987654321 -> 16492674416640 - outputBuffer[5] = bitfieldInsert(base, insert, 40, 4); // 0xF000000000 -> 10477124133360 - - // Test with a vector - vector base4 = vector(base, base, base, base); - vector insert4 = vector(insert, insert, insert, insert); - vector output4 = bitfieldInsert(base4, insert4, 4, 40); - outputBuffer[6] = output4.x; - outputBuffer[7] = output4.y; - outputBuffer[8] = output4.z; - outputBuffer[9] = output4.w; -} diff --git a/tests/language-feature/bitfield/bitfield-insert.slang b/tests/language-feature/bitfield/bitfield-insert.slang new file mode 100644 index 0000000000..b7d11c13df --- /dev/null +++ b/tests/language-feature/bitfield/bitfield-insert.slang @@ -0,0 +1,100 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compile-arg -skip-spirv-validation -emit-spirv-directly +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-dx12 -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-mtl +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda + +// CHECK: 8765432F +// CHECK-NEXT: 876543F1 +// CHECK-NEXT: 87654F21 +// CHECK-NEXT: 8765F321 +// CHECK-NEXT: A8 +// CHECK-NEXT: 3FC0 +// CHECK-NEXT: 123456F8 +// CHECK-NEXT: 9ABCDE60 +// CHECK-NEXT: 87654331 +// CHECK-NEXT: FEDCBA68 + +// CHECK-NEXT: 7654321A +// CHECK-NEXT: FEDCBA98 +// CHECK-NEXT: 76543210 +// CHECK-NEXT: FEDCBA9A +// CHECK-NEXT: 76543210 +// CHECK-NEXT: FEDABA98 +// CHECK-NEXT: 76543210 +// CHECK-NEXT: AEDCBA98 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 0 +// CHECK-NEXT: F00 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 +// CHECK-NEXT: 654321F0 +// CHECK-NEXT: 987 + +//TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9], stride=4):out,name=i32Buffer +RWStructuredBuffer i32Buffer; + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=i64Buffer +RWStructuredBuffer i64Buffer; + +[numthreads(1, 1, 1)] +void computeMain() +{ + // 32-bit tests + { + // Simple hex insertion to test, varying the offset. + uint base = 0x87654321; + uint value = 0xABCDEF; + i32Buffer[0] = bitfieldInsert(base, value, 4 * 0, 4); // 0x8765432F -> 2271560495 + i32Buffer[1] = bitfieldInsert(base, value, 4 * 1, 4); // 0x876543F1 -> 2271560689 + i32Buffer[2] = bitfieldInsert(base, value, 4 * 2, 4); // 0x8765F321 -> 2271563553 + i32Buffer[3] = bitfieldInsert(base, value, 4 * 3, 4); // 0x87F54321 -> 2271605537 + + // Test with varying bit length + base = 0; + value = 0b101010; + i32Buffer[4] = bitfieldInsert(base, value, 2, 6); // 0b10101000 -> 1005526666 + value = 0b11111111; + i32Buffer[5] = bitfieldInsert(base, value, 6, 8); // 0b11111111000000 -> 1005519841 + + // Test with a vector + uint4 base4 = uint4(0x12345678, 0x9abcdef0, 0x87654321, 0xfedcba98); + uint4 value4 = uint4(0xABCDEF, 0x123456, 0x876543, 0x123456); + uint4 output4 = bitfieldInsert(base4, value4, 4, 4); + i32Buffer[6] = output4.x; + i32Buffer[7] = output4.y; + i32Buffer[8] = output4.z; + i32Buffer[9] = output4.w; + } + + // 64-bit tests + { + // Simple hex insertion to test, varying the offset. + uint64_t base = 0xFEDCBA9876543210ull; + uint64_t insert = 0xAull; + i64Buffer[0] = bitfieldInsert(base, insert, 4 * 0, 4); // 0xFEDCBA987654321Aull -> 2271560495 + i64Buffer[1] = bitfieldInsert(base, insert, 4 * 8, 4); // 0xFEDCBA98A6543210ull -> 2271560689 + i64Buffer[2] = bitfieldInsert(base, insert, 4 * 12, 4); // 0xFEDCAA9876543210ull -> 2271563553 + i64Buffer[3] = bitfieldInsert(base, insert, 4 * 15, 4); // 0xAEDCBA9876543210ull -> 2271605537 + + // Test with varying bit length + base = 0; + insert = 0xFEDCBA987654321Full; + i64Buffer[4] = bitfieldInsert(base, insert, 4, 40); // 0xA987654321 -> 16492674416640 + i64Buffer[5] = bitfieldInsert(base, insert, 40, 4); // 0xF000000000 -> 10477124133360 + + // Test with a vector + vector base4 = vector(base, base, base, base); + vector insert4 = vector(insert, insert, insert, insert); + vector output4 = bitfieldInsert(base4, insert4, 4, 40); + i64Buffer[6] = output4.x; + i64Buffer[7] = output4.y; + i64Buffer[8] = output4.z; + i64Buffer[9] = output4.w; + } +} From 85618015eade8afbb5fa74aa923fcd7f645b58da Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Sun, 15 Sep 2024 12:19:01 -0700 Subject: [PATCH 15/17] adding 16-bit test for bitfield insert --- .../bitfield/bitfield-insert.slang | 67 +++++++++++++++---- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/tests/language-feature/bitfield/bitfield-insert.slang b/tests/language-feature/bitfield/bitfield-insert.slang index b7d11c13df..0794b0783a 100644 --- a/tests/language-feature/bitfield/bitfield-insert.slang +++ b/tests/language-feature/bitfield/bitfield-insert.slang @@ -4,7 +4,18 @@ //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cuda -// CHECK: 8765432F +// CHECK: 432D +// CHECK-NEXT: 43D1 +// CHECK-NEXT: 4D21 +// CHECK-NEXT: D321 +// CHECK-NEXT: A8 +// CHECK-NEXT: 3FC0 +// CHECK-NEXT: 12D4 +// CHECK-NEXT: FFFF9A4C +// CHECK-NEXT: FFFF8755 +// CHECK-NEXT: FFFFFE4C + +// CHECK-NEXT: 8765432F // CHECK-NEXT: 876543F1 // CHECK-NEXT: 87654F21 // CHECK-NEXT: 8765F321 @@ -36,6 +47,9 @@ // CHECK-NEXT: 654321F0 // CHECK-NEXT: 987 +//TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9], stride=4):out,name=i16Buffer +RWStructuredBuffer i16Buffer; + //TEST_INPUT:ubuffer(data=[0 1 2 3 4 5 6 7 8 9], stride=4):out,name=i32Buffer RWStructuredBuffer i32Buffer; @@ -45,22 +59,49 @@ RWStructuredBuffer i64Buffer; [numthreads(1, 1, 1)] void computeMain() { + // 16-bit tests + { + // Simple hex insertion to test, varying the offset. + uint16_t base = 0x4321; + uint16_t value = 0xABCD; + i16Buffer[0] = bitfieldInsert(base, value, 4 * 0, 4); // 0x432D + i16Buffer[1] = bitfieldInsert(base, value, 4 * 1, 4); // 0x43D1 + i16Buffer[2] = bitfieldInsert(base, value, 4 * 2, 4); // 0x4D21 + i16Buffer[3] = bitfieldInsert(base, value, 4 * 3, 4); // 0xD321 + + // Test with varying bit length + base = 0; + value = 0b101010; + i16Buffer[4] = bitfieldInsert(base, value, 2, 6); // 0b101010 00 -> 0xA8 + value = 0b11111111; + i16Buffer[5] = bitfieldInsert(base, value, 6, 8); // 0b11111111 000000 -> 0x3FC0 + + // Test with a vector + vector base4 = vector(0x1234, 0x9abc, 0x8765, 0xfedc); + vector value4 = vector(0xABCD, 0x1234, 0x8765, 0x1234); + vector output4 = bitfieldInsert(base4, value4, 4, 4); + i16Buffer[6] = output4.x; + i16Buffer[7] = output4.y; + i16Buffer[8] = output4.z; + i16Buffer[9] = output4.w; + } + // 32-bit tests { // Simple hex insertion to test, varying the offset. uint base = 0x87654321; uint value = 0xABCDEF; - i32Buffer[0] = bitfieldInsert(base, value, 4 * 0, 4); // 0x8765432F -> 2271560495 - i32Buffer[1] = bitfieldInsert(base, value, 4 * 1, 4); // 0x876543F1 -> 2271560689 - i32Buffer[2] = bitfieldInsert(base, value, 4 * 2, 4); // 0x8765F321 -> 2271563553 - i32Buffer[3] = bitfieldInsert(base, value, 4 * 3, 4); // 0x87F54321 -> 2271605537 + i32Buffer[0] = bitfieldInsert(base, value, 4 * 0, 4); // 0x8765432F + i32Buffer[1] = bitfieldInsert(base, value, 4 * 1, 4); // 0x876543F1 + i32Buffer[2] = bitfieldInsert(base, value, 4 * 2, 4); // 0x8765F321 + i32Buffer[3] = bitfieldInsert(base, value, 4 * 3, 4); // 0x87F54321 // Test with varying bit length base = 0; value = 0b101010; - i32Buffer[4] = bitfieldInsert(base, value, 2, 6); // 0b10101000 -> 1005526666 + i32Buffer[4] = bitfieldInsert(base, value, 2, 6); // 0b10101000 value = 0b11111111; - i32Buffer[5] = bitfieldInsert(base, value, 6, 8); // 0b11111111000000 -> 1005519841 + i32Buffer[5] = bitfieldInsert(base, value, 6, 8); // 0b11111111000000 // Test with a vector uint4 base4 = uint4(0x12345678, 0x9abcdef0, 0x87654321, 0xfedcba98); @@ -77,16 +118,16 @@ void computeMain() // Simple hex insertion to test, varying the offset. uint64_t base = 0xFEDCBA9876543210ull; uint64_t insert = 0xAull; - i64Buffer[0] = bitfieldInsert(base, insert, 4 * 0, 4); // 0xFEDCBA987654321Aull -> 2271560495 - i64Buffer[1] = bitfieldInsert(base, insert, 4 * 8, 4); // 0xFEDCBA98A6543210ull -> 2271560689 - i64Buffer[2] = bitfieldInsert(base, insert, 4 * 12, 4); // 0xFEDCAA9876543210ull -> 2271563553 - i64Buffer[3] = bitfieldInsert(base, insert, 4 * 15, 4); // 0xAEDCBA9876543210ull -> 2271605537 + i64Buffer[0] = bitfieldInsert(base, insert, 4 * 0, 4); // 0xFEDCBA987654321Aull + i64Buffer[1] = bitfieldInsert(base, insert, 4 * 8, 4); // 0xFEDCBA98A6543210ull + i64Buffer[2] = bitfieldInsert(base, insert, 4 * 12, 4); // 0xFEDCAA9876543210ull + i64Buffer[3] = bitfieldInsert(base, insert, 4 * 15, 4); // 0xAEDCBA9876543210ull // Test with varying bit length base = 0; insert = 0xFEDCBA987654321Full; - i64Buffer[4] = bitfieldInsert(base, insert, 4, 40); // 0xA987654321 -> 16492674416640 - i64Buffer[5] = bitfieldInsert(base, insert, 40, 4); // 0xF000000000 -> 10477124133360 + i64Buffer[4] = bitfieldInsert(base, insert, 4, 40); // 0xA987654321 + i64Buffer[5] = bitfieldInsert(base, insert, 40, 4); // 0xF000000000 // Test with a vector vector base4 = vector(base, base, base, base); From fc0f6c8ad3d301a9843b4820544b79ce27391669 Mon Sep 17 00:00:00 2001 From: Nate Morrical Date: Sun, 15 Sep 2024 13:40:28 -0700 Subject: [PATCH 16/17] fixing sign in insert test --- .../language-feature/bitfield/bitfield-insert.slang | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/language-feature/bitfield/bitfield-insert.slang b/tests/language-feature/bitfield/bitfield-insert.slang index 0794b0783a..ee389bcc6c 100644 --- a/tests/language-feature/bitfield/bitfield-insert.slang +++ b/tests/language-feature/bitfield/bitfield-insert.slang @@ -11,9 +11,9 @@ // CHECK-NEXT: A8 // CHECK-NEXT: 3FC0 // CHECK-NEXT: 12D4 -// CHECK-NEXT: FFFF9A4C -// CHECK-NEXT: FFFF8755 -// CHECK-NEXT: FFFFFE4C +// CHECK-NEXT: 9A4C +// CHECK-NEXT: 8755 +// CHECK-NEXT: FE4C // CHECK-NEXT: 8765432F // CHECK-NEXT: 876543F1 @@ -77,9 +77,9 @@ void computeMain() i16Buffer[5] = bitfieldInsert(base, value, 6, 8); // 0b11111111 000000 -> 0x3FC0 // Test with a vector - vector base4 = vector(0x1234, 0x9abc, 0x8765, 0xfedc); - vector value4 = vector(0xABCD, 0x1234, 0x8765, 0x1234); - vector output4 = bitfieldInsert(base4, value4, 4, 4); + vector base4 = vector(0x1234, 0x9abc, 0x8765, 0xfedc); + vector value4 = vector(0xABCD, 0x1234, 0x8765, 0x1234); + vector output4 = bitfieldInsert(base4, value4, 4, 4); i16Buffer[6] = output4.x; i16Buffer[7] = output4.y; i16Buffer[8] = output4.z; From b5e3ca57f0ce83ecba32f1a18dd6b1a79289118a Mon Sep 17 00:00:00 2001 From: "Nathan V. Morrical" Date: Sun, 15 Sep 2024 16:01:54 -0700 Subject: [PATCH 17/17] Apply suggestions from code review --- source/slang/slang-emit-c-like.cpp | 3 ++- source/slang/slang-emit-glsl.cpp | 6 ++++-- source/slang/slang-emit-spirv.cpp | 6 ++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 097e4bb288..f48167ad39 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3810,7 +3810,8 @@ void CLikeSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) } String one; - switch(bitWidth) { + switch(bitWidth) + { case 8: one = "uint8_t(1)"; break; case 16: one = "uint16_t(1)"; break; case 32: one = "uint32_t(1)"; break; diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index df850f7df4..ce88218655 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -2449,7 +2449,8 @@ void GLSLSourceEmitter::emitFuncDecorationImpl(IRDecoration* decoration) } } -void GLSLSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) { +void GLSLSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) +{ m_writer->emit("bitfieldExtract("); emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); m_writer->emit(","); @@ -2459,7 +2460,8 @@ void GLSLSourceEmitter::emitBitfieldExtractImpl(IRInst* inst) { m_writer->emit(")"); } -void GLSLSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) { +void GLSLSourceEmitter::emitBitfieldInsertImpl(IRInst* inst) +{ m_writer->emit("bitfieldInsert("); emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); m_writer->emit(","); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index e2e501adf8..dbd8371d1c 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -5600,7 +5600,8 @@ struct SPIRVEmitContext return emitInst(parent, inst, SpvOpConvertUToPtr, inst->getFullType(), kResultID, inst->getOperand(0)); } - SpvInst* emitBitfieldExtract(SpvInstParent* parent, IRInst* inst) { + SpvInst* emitBitfieldExtract(SpvInstParent* parent, IRInst* inst) + { auto dataType = inst->getDataType(); IRVectorType* vectorType = as(dataType); Slang::IRType* elementType = dataType; @@ -5617,7 +5618,8 @@ struct SPIRVEmitContext inst->getOperand(0), inst->getOperand(1), inst->getOperand(2)); } - SpvInst* emitBitfieldInsert(SpvInstParent* parent, IRInst* inst) { + SpvInst* emitBitfieldInsert(SpvInstParent* parent, IRInst* inst) + { auto dataType = inst->getDataType(); IRVectorType* vectorType = as(dataType); Slang::IRType* elementType = dataType;