From 6f57e47a9e1675b011f023277b47cfc768d30da8 Mon Sep 17 00:00:00 2001 From: kaizhangNV <149626564+kaizhangNV@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:06:30 -0600 Subject: [PATCH] Implement bitcast for 64-bit date type (#5895) Close #5470 * implement bitcast for 64-bit date type * Move 'ensurePrelude' to base class to remove duplication * Assert on 'double' type for Metal target, as Metal doesn't have 'double' support --- source/slang/slang-emit-c-like.cpp | 11 +++++ source/slang/slang-emit-c-like.h | 5 +++ source/slang/slang-emit-glsl.cpp | 26 +++++++++++ source/slang/slang-emit-hlsl.cpp | 37 ++++++++++++---- source/slang/slang-emit-metal.cpp | 16 ++----- source/slang/slang-emit-metal.h | 4 -- source/slang/slang-emit-wgsl.cpp | 12 ------ source/slang/slang-emit-wgsl.h | 4 -- tests/compute/bitcast-64bit.slang | 43 +++++++++++++++++++ .../compute/bitcast-64bit.slang.expected.txt | 5 +++ 10 files changed, 121 insertions(+), 42 deletions(-) create mode 100644 tests/compute/bitcast-64bit.slang create mode 100644 tests/compute/bitcast-64bit.slang.expected.txt diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index f38adc67e3..b70069d425 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -5137,4 +5137,15 @@ void CLikeSourceEmitter::emitModuleImpl(IRModule* module, DiagnosticSink* sink) executeEmitActions(actions); } +void CLikeSourceEmitter::ensurePrelude(const char* preludeText) +{ + IRStringLit* stringLit; + if (!m_builtinPreludes.tryGetValue(preludeText, stringLit)) + { + IRBuilder builder(m_irModule); + stringLit = builder.getStringValue(UnownedStringSlice(preludeText)); + m_builtinPreludes[preludeText] = stringLit; + } + m_requiredPreludes.add(stringLit); +} } // namespace Slang diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index 7f6f329233..dd8e276740 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -678,6 +678,9 @@ class CLikeSourceEmitter : public SourceEmitterBase String _emitLiteralOneWithType(int bitWidth); + + virtual void ensurePrelude(const char* preludeText); + CodeGenContext* m_codeGenContext = nullptr; IRModule* m_irModule = nullptr; @@ -723,6 +726,8 @@ class CLikeSourceEmitter : public SourceEmitterBase { String requireComputeDerivatives; } m_requiredAfter; + + Dictionary m_builtinPreludes; }; } // namespace Slang diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 2c2447c530..d6f3795e3e 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -2030,6 +2030,32 @@ bool GLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu emitType(inst->getDataType()); } break; + case BaseType::Int64: + if (fromType == BaseType::Double) + { + m_writer->emit("int64_t(doubleBitsToInt64("); + emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); + m_writer->emit("))"); + return true; + } + else + { + emitType(inst->getDataType()); + } + break; + case BaseType::UInt64: + if (fromType == BaseType::Double) + { + m_writer->emit("uint64_t(doubleBitsToUint64("); + emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); + m_writer->emit("))"); + return true; + } + else + { + emitType(inst->getDataType()); + } + break; case BaseType::Half: switch (fromType) { diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index 824680b72f..c43f075b2f 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -11,6 +11,23 @@ namespace Slang { +static const char* kHLSLBuiltInPrelude64BitCast = R"( +uint64_t _slang_asuint64(double x) +{ + uint32_t low; + uint32_t high; + asuint(x, low, high); + return ((uint64_t)high << 32) | low; +} + +double _slang_asdouble(uint64_t x) +{ + uint32_t low = x & 0xFFFFFFFF; + uint32_t high = x >> 32; + return asdouble(low, high); +} +)"; + void HLSLSourceEmitter::_emitHLSLDecorationSingleString( const char* name, IRFunc* entryPoint, @@ -822,17 +839,12 @@ bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu // // There is no current function (it seems) // for bit-casting an `int16_t` to a `half`. - // - // TODO: There is an `asdouble` function - // for converting two 32-bit integer values into - // one `double`. We could use that for - // bit casts of 64-bit values with a bit of - // extra work, but doing so might be best - // handled in an IR pass that legalizes - // bit-casts. - // m_writer->emit("asfloat"); break; + case BaseType::Double: + ensurePrelude(kHLSLBuiltInPrelude64BitCast); + m_writer->emit("_slang_asdouble"); + break; } m_writer->emit("("); int closeCount = 1; @@ -844,6 +856,8 @@ bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu diagnoseUnhandledInst(inst); break; + case BaseType::Int64: + case BaseType::UInt64: case BaseType::UInt: case BaseType::Int: case BaseType::Bool: @@ -860,6 +874,11 @@ bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu m_writer->emit("asuint16("); closeCount++; break; + case BaseType::Double: + ensurePrelude(kHLSLBuiltInPrelude64BitCast); + m_writer->emit("_slang_asuint64("); + closeCount++; + break; } emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); diff --git a/source/slang/slang-emit-metal.cpp b/source/slang/slang-emit-metal.cpp index 45a9e60ad3..282d8f95c0 100644 --- a/source/slang/slang-emit-metal.cpp +++ b/source/slang/slang-emit-metal.cpp @@ -263,18 +263,6 @@ void MetalSourceEmitter::emitEntryPointAttributesImpl( } } -void MetalSourceEmitter::ensurePrelude(const char* preludeText) -{ - IRStringLit* stringLit; - if (!m_builtinPreludes.tryGetValue(preludeText, stringLit)) - { - IRBuilder builder(m_irModule); - stringLit = builder.getStringValue(UnownedStringSlice(preludeText)); - m_builtinPreludes[preludeText] = stringLit; - } - m_requiredPreludes.add(stringLit); -} - void MetalSourceEmitter::emitMemoryOrderOperand(IRInst* inst) { auto memoryOrder = (IRMemoryOrder)getIntVal(inst); @@ -1065,7 +1053,6 @@ void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type) case kIROp_UInt8Type: case kIROp_UIntType: case kIROp_FloatType: - case kIROp_DoubleType: case kIROp_HalfType: { m_writer->emit(getDefaultBuiltinTypeName(type->getOp())); @@ -1093,6 +1080,9 @@ void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type) m_writer->emit(getName(type)); return; + case kIROp_DoubleType: + SLANG_UNEXPECTED("'double' type emitted"); + return; case kIROp_VectorType: { auto vecType = (IRVectorType*)type; diff --git a/source/slang/slang-emit-metal.h b/source/slang/slang-emit-metal.h index 17562b1c49..b67a5b8017 100644 --- a/source/slang/slang-emit-metal.h +++ b/source/slang/slang-emit-metal.h @@ -22,13 +22,9 @@ class MetalSourceEmitter : public CLikeSourceEmitter virtual RefObject* getExtensionTracker() SLANG_OVERRIDE { return m_extensionTracker; } - Dictionary m_builtinPreludes; - protected: RefPtr m_extensionTracker; - void ensurePrelude(const char* preludeText); - void emitMemoryOrderOperand(IRInst* inst); virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type) SLANG_OVERRIDE; diff --git a/source/slang/slang-emit-wgsl.cpp b/source/slang/slang-emit-wgsl.cpp index 0e45fd4cf7..da5e383277 100644 --- a/source/slang/slang-emit-wgsl.cpp +++ b/source/slang/slang-emit-wgsl.cpp @@ -49,18 +49,6 @@ fn _slang_getNan() -> f32 } )"; -void WGSLSourceEmitter::ensurePrelude(const char* preludeText) -{ - IRStringLit* stringLit; - if (!m_builtinPreludes.tryGetValue(preludeText, stringLit)) - { - IRBuilder builder(m_irModule); - stringLit = builder.getStringValue(UnownedStringSlice(preludeText)); - m_builtinPreludes[preludeText] = stringLit; - } - m_requiredPreludes.add(stringLit); -} - void WGSLSourceEmitter::emitSwitchCaseSelectorsImpl( const SwitchRegion::Case* const currentCase, const bool isDefault) diff --git a/source/slang/slang-emit-wgsl.h b/source/slang/slang-emit-wgsl.h index 28311aa276..390ee876d9 100644 --- a/source/slang/slang-emit-wgsl.h +++ b/source/slang/slang-emit-wgsl.h @@ -57,10 +57,6 @@ class WGSLSourceEmitter : public CLikeSourceEmitter void emit(const AddressSpace addressSpace); virtual bool shouldFoldInstIntoUseSites(IRInst* inst) SLANG_OVERRIDE; - Dictionary m_builtinPreludes; - -protected: - void ensurePrelude(const char* preludeText); private: bool maybeEmitSystemSemantic(IRInst* inst); diff --git a/tests/compute/bitcast-64bit.slang b/tests/compute/bitcast-64bit.slang new file mode 100644 index 0000000000..410fa768a5 --- /dev/null +++ b/tests/compute/bitcast-64bit.slang @@ -0,0 +1,43 @@ +//TEST(compute):COMPARE_COMPUTE_EX:-vk -compute -shaderobj -emit-spirv-via-glsl -output-using-type +//TEST(compute):COMPARE_COMPUTE_EX:-vk -compute -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -d3d12 -profile cs_6_6 -use-dxil -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj -output-using-type + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name=gOutputBuffer +RWStructuredBuffer gOutputBuffer; + +int64_t icast(double x) +{ + return bit_cast(x); +} + +int64_t icast(uint64_t x) +{ + return bit_cast(x); +} + +uint64_t ucast(double x) +{ + return bit_cast(x); +} + +uint64_t ucast(int64_t x) +{ + return bit_cast(x); +} + +[numthreads(1, 1, 1)] +[shader("compute")] +void computeMain() +{ + double t1 = -1.0; + uint64_t t2 = 2; + gOutputBuffer[0] = icast(t1); // 0xBFF0000000000000 => 13830554455654793216 + gOutputBuffer[1] = icast(t2); // 0x0000000000000002 => 2 + + double t3 = 3.0; + int64_t t4 = -4; + gOutputBuffer[2] = ucast(t3); // 0x4008000000000000 => 4613937818241073152 + gOutputBuffer[3] = ucast(t4); // 0xFFFFFFFFFFFFFFFC => 18446744073709551612 +} diff --git a/tests/compute/bitcast-64bit.slang.expected.txt b/tests/compute/bitcast-64bit.slang.expected.txt new file mode 100644 index 0000000000..cb9a9f87d9 --- /dev/null +++ b/tests/compute/bitcast-64bit.slang.expected.txt @@ -0,0 +1,5 @@ +type: uint64_t +13830554455654793216 +2 +4613937818241073152 +18446744073709551612