Skip to content

Commit 6f57e47

Browse files
authored
Implement bitcast for 64-bit date type (shader-slang#5895)
Close shader-slang#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
1 parent 49e912a commit 6f57e47

10 files changed

+121
-42
lines changed

source/slang/slang-emit-c-like.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -5137,4 +5137,15 @@ void CLikeSourceEmitter::emitModuleImpl(IRModule* module, DiagnosticSink* sink)
51375137
executeEmitActions(actions);
51385138
}
51395139

5140+
void CLikeSourceEmitter::ensurePrelude(const char* preludeText)
5141+
{
5142+
IRStringLit* stringLit;
5143+
if (!m_builtinPreludes.tryGetValue(preludeText, stringLit))
5144+
{
5145+
IRBuilder builder(m_irModule);
5146+
stringLit = builder.getStringValue(UnownedStringSlice(preludeText));
5147+
m_builtinPreludes[preludeText] = stringLit;
5148+
}
5149+
m_requiredPreludes.add(stringLit);
5150+
}
51405151
} // namespace Slang

source/slang/slang-emit-c-like.h

+5
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,9 @@ class CLikeSourceEmitter : public SourceEmitterBase
678678

679679
String _emitLiteralOneWithType(int bitWidth);
680680

681+
682+
virtual void ensurePrelude(const char* preludeText);
683+
681684
CodeGenContext* m_codeGenContext = nullptr;
682685
IRModule* m_irModule = nullptr;
683686

@@ -723,6 +726,8 @@ class CLikeSourceEmitter : public SourceEmitterBase
723726
{
724727
String requireComputeDerivatives;
725728
} m_requiredAfter;
729+
730+
Dictionary<const char*, IRStringLit*> m_builtinPreludes;
726731
};
727732

728733
} // namespace Slang

source/slang/slang-emit-glsl.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,32 @@ bool GLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu
20302030
emitType(inst->getDataType());
20312031
}
20322032
break;
2033+
case BaseType::Int64:
2034+
if (fromType == BaseType::Double)
2035+
{
2036+
m_writer->emit("int64_t(doubleBitsToInt64(");
2037+
emitOperand(inst->getOperand(0), getInfo(EmitOp::General));
2038+
m_writer->emit("))");
2039+
return true;
2040+
}
2041+
else
2042+
{
2043+
emitType(inst->getDataType());
2044+
}
2045+
break;
2046+
case BaseType::UInt64:
2047+
if (fromType == BaseType::Double)
2048+
{
2049+
m_writer->emit("uint64_t(doubleBitsToUint64(");
2050+
emitOperand(inst->getOperand(0), getInfo(EmitOp::General));
2051+
m_writer->emit("))");
2052+
return true;
2053+
}
2054+
else
2055+
{
2056+
emitType(inst->getDataType());
2057+
}
2058+
break;
20332059
case BaseType::Half:
20342060
switch (fromType)
20352061
{

source/slang/slang-emit-hlsl.cpp

+28-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@
1111
namespace Slang
1212
{
1313

14+
static const char* kHLSLBuiltInPrelude64BitCast = R"(
15+
uint64_t _slang_asuint64(double x)
16+
{
17+
uint32_t low;
18+
uint32_t high;
19+
asuint(x, low, high);
20+
return ((uint64_t)high << 32) | low;
21+
}
22+
23+
double _slang_asdouble(uint64_t x)
24+
{
25+
uint32_t low = x & 0xFFFFFFFF;
26+
uint32_t high = x >> 32;
27+
return asdouble(low, high);
28+
}
29+
)";
30+
1431
void HLSLSourceEmitter::_emitHLSLDecorationSingleString(
1532
const char* name,
1633
IRFunc* entryPoint,
@@ -822,17 +839,12 @@ bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu
822839
//
823840
// There is no current function (it seems)
824841
// for bit-casting an `int16_t` to a `half`.
825-
//
826-
// TODO: There is an `asdouble` function
827-
// for converting two 32-bit integer values into
828-
// one `double`. We could use that for
829-
// bit casts of 64-bit values with a bit of
830-
// extra work, but doing so might be best
831-
// handled in an IR pass that legalizes
832-
// bit-casts.
833-
//
834842
m_writer->emit("asfloat");
835843
break;
844+
case BaseType::Double:
845+
ensurePrelude(kHLSLBuiltInPrelude64BitCast);
846+
m_writer->emit("_slang_asdouble");
847+
break;
836848
}
837849
m_writer->emit("(");
838850
int closeCount = 1;
@@ -844,6 +856,8 @@ bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu
844856
diagnoseUnhandledInst(inst);
845857
break;
846858

859+
case BaseType::Int64:
860+
case BaseType::UInt64:
847861
case BaseType::UInt:
848862
case BaseType::Int:
849863
case BaseType::Bool:
@@ -860,6 +874,11 @@ bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu
860874
m_writer->emit("asuint16(");
861875
closeCount++;
862876
break;
877+
case BaseType::Double:
878+
ensurePrelude(kHLSLBuiltInPrelude64BitCast);
879+
m_writer->emit("_slang_asuint64(");
880+
closeCount++;
881+
break;
863882
}
864883

865884
emitOperand(inst->getOperand(0), getInfo(EmitOp::General));

source/slang/slang-emit-metal.cpp

+3-13
Original file line numberDiff line numberDiff line change
@@ -263,18 +263,6 @@ void MetalSourceEmitter::emitEntryPointAttributesImpl(
263263
}
264264
}
265265

266-
void MetalSourceEmitter::ensurePrelude(const char* preludeText)
267-
{
268-
IRStringLit* stringLit;
269-
if (!m_builtinPreludes.tryGetValue(preludeText, stringLit))
270-
{
271-
IRBuilder builder(m_irModule);
272-
stringLit = builder.getStringValue(UnownedStringSlice(preludeText));
273-
m_builtinPreludes[preludeText] = stringLit;
274-
}
275-
m_requiredPreludes.add(stringLit);
276-
}
277-
278266
void MetalSourceEmitter::emitMemoryOrderOperand(IRInst* inst)
279267
{
280268
auto memoryOrder = (IRMemoryOrder)getIntVal(inst);
@@ -1065,7 +1053,6 @@ void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type)
10651053
case kIROp_UInt8Type:
10661054
case kIROp_UIntType:
10671055
case kIROp_FloatType:
1068-
case kIROp_DoubleType:
10691056
case kIROp_HalfType:
10701057
{
10711058
m_writer->emit(getDefaultBuiltinTypeName(type->getOp()));
@@ -1093,6 +1080,9 @@ void MetalSourceEmitter::emitSimpleTypeImpl(IRType* type)
10931080
m_writer->emit(getName(type));
10941081
return;
10951082

1083+
case kIROp_DoubleType:
1084+
SLANG_UNEXPECTED("'double' type emitted");
1085+
return;
10961086
case kIROp_VectorType:
10971087
{
10981088
auto vecType = (IRVectorType*)type;

source/slang/slang-emit-metal.h

-4
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,9 @@ class MetalSourceEmitter : public CLikeSourceEmitter
2222

2323
virtual RefObject* getExtensionTracker() SLANG_OVERRIDE { return m_extensionTracker; }
2424

25-
Dictionary<const char*, IRStringLit*> m_builtinPreludes;
26-
2725
protected:
2826
RefPtr<MetalExtensionTracker> m_extensionTracker;
2927

30-
void ensurePrelude(const char* preludeText);
31-
3228
void emitMemoryOrderOperand(IRInst* inst);
3329
virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type)
3430
SLANG_OVERRIDE;

source/slang/slang-emit-wgsl.cpp

-12
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,6 @@ fn _slang_getNan() -> f32
4949
}
5050
)";
5151

52-
void WGSLSourceEmitter::ensurePrelude(const char* preludeText)
53-
{
54-
IRStringLit* stringLit;
55-
if (!m_builtinPreludes.tryGetValue(preludeText, stringLit))
56-
{
57-
IRBuilder builder(m_irModule);
58-
stringLit = builder.getStringValue(UnownedStringSlice(preludeText));
59-
m_builtinPreludes[preludeText] = stringLit;
60-
}
61-
m_requiredPreludes.add(stringLit);
62-
}
63-
6452
void WGSLSourceEmitter::emitSwitchCaseSelectorsImpl(
6553
const SwitchRegion::Case* const currentCase,
6654
const bool isDefault)

source/slang/slang-emit-wgsl.h

-4
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ class WGSLSourceEmitter : public CLikeSourceEmitter
5757
void emit(const AddressSpace addressSpace);
5858

5959
virtual bool shouldFoldInstIntoUseSites(IRInst* inst) SLANG_OVERRIDE;
60-
Dictionary<const char*, IRStringLit*> m_builtinPreludes;
61-
62-
protected:
63-
void ensurePrelude(const char* preludeText);
6460

6561
private:
6662
bool maybeEmitSystemSemantic(IRInst* inst);

tests/compute/bitcast-64bit.slang

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//TEST(compute):COMPARE_COMPUTE_EX:-vk -compute -shaderobj -emit-spirv-via-glsl -output-using-type
2+
//TEST(compute):COMPARE_COMPUTE_EX:-vk -compute -shaderobj -output-using-type
3+
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -d3d12 -profile cs_6_6 -use-dxil -shaderobj -output-using-type
4+
//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj -output-using-type
5+
//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj -output-using-type
6+
7+
//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name=gOutputBuffer
8+
RWStructuredBuffer<uint64_t> gOutputBuffer;
9+
10+
int64_t icast(double x)
11+
{
12+
return bit_cast<int64_t>(x);
13+
}
14+
15+
int64_t icast(uint64_t x)
16+
{
17+
return bit_cast<int64_t>(x);
18+
}
19+
20+
uint64_t ucast(double x)
21+
{
22+
return bit_cast<uint64_t>(x);
23+
}
24+
25+
uint64_t ucast(int64_t x)
26+
{
27+
return bit_cast<uint64_t>(x);
28+
}
29+
30+
[numthreads(1, 1, 1)]
31+
[shader("compute")]
32+
void computeMain()
33+
{
34+
double t1 = -1.0;
35+
uint64_t t2 = 2;
36+
gOutputBuffer[0] = icast(t1); // 0xBFF0000000000000 => 13830554455654793216
37+
gOutputBuffer[1] = icast(t2); // 0x0000000000000002 => 2
38+
39+
double t3 = 3.0;
40+
int64_t t4 = -4;
41+
gOutputBuffer[2] = ucast(t3); // 0x4008000000000000 => 4613937818241073152
42+
gOutputBuffer[3] = ucast(t4); // 0xFFFFFFFFFFFFFFFC => 18446744073709551612
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type: uint64_t
2+
13830554455654793216
3+
2
4+
4613937818241073152
5+
18446744073709551612

0 commit comments

Comments
 (0)