diff options
| author | Yong He <yonghe@outlook.com> | 2022-03-18 09:35:23 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-18 09:35:23 -0700 |
| commit | 2e1a84add57efd9f8a50a88d0569a48ae4b6d834 (patch) | |
| tree | 3e1ce103fa75a62eb3f1efd3c832e468bc9e8aed | |
| parent | 42ca6758046e11451b0788092f9c95fc7f788da6 (diff) | |
Fix type truncation during SCCP. (#2163)
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 72 | ||||
| -rw-r--r-- | source/slang/slang-ir-sccp.cpp | 22 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 42 | ||||
| -rw-r--r-- | tests/ir/scalar-truncate.slang | 16 | ||||
| -rw-r--r-- | tests/ir/scalar-truncate.slang.expected.txt | 4 |
5 files changed, 90 insertions, 66 deletions
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 6b77cba6a..d3dd0e5b8 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -850,60 +850,40 @@ void CLikeSourceEmitter::emitSimpleValueImpl(IRInst* inst) switch (type->getBaseType()) { default: - case BaseType::Int8: - case BaseType::Int16: + case BaseType::Int: { - // NOTE! This hack is required, otherwise we get different results across targets. - // You'd hope that outputting L suffix would be enough to make this work, and not require a cast, but testing shows L suffix - // does not have the same meaning across targets. - // - // For example - // - // uint64_t v = 0x80000000; - // - // When output this becomes... - // v_0 = uint64_t(-2147483648L); - // - // On MSVC/Gcc/Clang this is equal to 0x80000000, elsewhere it's 0xffffffff80000000 elsewhere. - // Note that '-' isn't the issue because v0 = uint64_t(0x80000000L); produces the same issue - // - // If we use a cast, we get the same result across targets (which is why the hack is here). - // - // Why? It's not clear - it seems likely that it's related to the order of how the promotion takes place. - // - // If we convert from int32_t -> uint64_t, there are two possible scenarios - // 1) int32_t -> int64_t -> uint64_t (ie widen first then do sign type change) - // 2) int32_t -> uint32_t -> uint64_t (ie do sign type change then widen) - // - // 2 would produce what we see on C++, 1 what we see everywhere else. - // - // Why having a cast or having a suffix would make a difference though is not clear. It is also possible that the - // L suffix is just ignored, and the literal is really a 'non typed' int literal in C++. - - // This little hack is needed for gcc that if we have the expression - // int(-0x80000000) we get the warning: warning : integer overflow in expression [-Woverflow] - // 0x80000000 and -0x80000000 mean the same thing when casted to 32 bit int, so we just flip the value here. - IRIntegerValue value = litInst->value.intVal; - value = (value == -0x80000000ll) ? -value : value; - m_writer->emit("int("); - m_writer->emit(value); + m_writer->emit(int32_t(litInst->value.intVal)); + m_writer->emit(")"); + return; + } + case BaseType::Int8: + { + m_writer->emit("int8_t("); + m_writer->emit(int8_t(litInst->value.intVal)); + m_writer->emit(")"); + return; + } + case BaseType::Int16: + { + m_writer->emit("int16_t("); + m_writer->emit(int16_t(litInst->value.intVal)); m_writer->emit(")"); return; } case BaseType::UInt8: - { - m_writer->emit(UInt(uint8_t(litInst->value.intVal))); - m_writer->emit("U"); - break; - } + { + m_writer->emit(UInt(uint8_t(litInst->value.intVal))); + m_writer->emit("U"); + break; + } case BaseType::UInt16: - { - m_writer->emit(UInt(uint16_t(litInst->value.intVal))); - m_writer->emit("U"); - break; - } + { + m_writer->emit(UInt(uint16_t(litInst->value.intVal))); + m_writer->emit("U"); + break; + } case BaseType::UInt: { m_writer->emit(UInt(uint32_t(litInst->value.intVal))); diff --git a/source/slang/slang-ir-sccp.cpp b/source/slang/slang-ir-sccp.cpp index 28f262c1a..e724d0d88 100644 --- a/source/slang/slang-ir-sccp.cpp +++ b/source/slang/slang-ir-sccp.cpp @@ -288,7 +288,11 @@ struct SCCPContext { SLANG_SCCP_RETURN_IF_NONE_OR_ANY(v0) auto irConstant = as<IRConstant>(v0.value); + IRInst* resultVal = nullptr; + if (type->getOp() == irConstant->getOp()) + return LatticeVal::getConstant(irConstant); + switch (type->getOp()) { case kIROp_Int8Type: @@ -309,24 +313,6 @@ struct SCCPContext case kIROp_BoolLit: { IRIntegerValue intVal = irConstant->value.intVal; - switch (type->getOp()) - { - case kIROp_Int8Type: - case kIROp_UInt8Type: - intVal = intVal & 0xFF; - break; - case kIROp_Int16Type: - case kIROp_UInt16Type: - intVal = intVal & 0xFFFF; - break; - case kIROp_IntType: - case kIROp_UIntType: - case kIROp_BoolType: - intVal = intVal & 0xFFFFFFFF; - break; - default: - break; - } resultVal = getBuilder()->getIntValue(type, (IRIntegerValue)intVal); } break; diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 721488f82..bb1b0a9d2 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -2081,7 +2081,32 @@ namespace Slang memset(&keyInst, 0, sizeof(keyInst)); keyInst.m_op = kIROp_IntLit; keyInst.typeUse.usedValue = type; - keyInst.value.intVal = inValue; + // Truncate the input value based on `type`. + switch (type->getOp()) + { + case kIROp_Int8Type: + keyInst.value.intVal = static_cast<int8_t>(inValue); + break; + case kIROp_Int16Type: + keyInst.value.intVal = static_cast<int16_t>(inValue); + break; + case kIROp_IntType: + keyInst.value.intVal = static_cast<int32_t>(inValue); + break; + case kIROp_UInt8Type: + keyInst.value.intVal = static_cast<uint8_t>(inValue); + break; + case kIROp_UInt16Type: + keyInst.value.intVal = static_cast<uint16_t>(inValue); + break; + case kIROp_BoolType: + case kIROp_UIntType: + keyInst.value.intVal = static_cast<uint32_t>(inValue); + break; + default: + keyInst.value.intVal = inValue; + break; + } return _findOrEmitConstant(keyInst); } @@ -2091,7 +2116,20 @@ namespace Slang memset(&keyInst, 0, sizeof(keyInst)); keyInst.m_op = kIROp_FloatLit; keyInst.typeUse.usedValue = type; - keyInst.value.floatVal = inValue; + // Truncate the input value based on `type`. + switch (type->getOp()) + { + case kIROp_FloatType: + keyInst.value.floatVal = static_cast<float>(inValue); + break; + case kIROp_HalfType: + keyInst.value.floatVal = HalfToFloat(FloatToHalf((float)inValue)); + break; + default: + keyInst.value.floatVal = inValue; + break; + } + return _findOrEmitConstant(keyInst); } diff --git a/tests/ir/scalar-truncate.slang b/tests/ir/scalar-truncate.slang new file mode 100644 index 000000000..9d9d33261 --- /dev/null +++ b/tests/ir/scalar-truncate.slang @@ -0,0 +1,16 @@ +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + { + int16_t a = 30000; // 0x00007530 -> 0x7530 (30000) in 16-bit. + int16_t b = -200000; // 0xfffcf2c0 -> Truncated to 0xf2c0 (-3392) in 16-bit. + outputBuffer[0] = asuint((int)a); + outputBuffer[1] = asuint((int)b); + } +} diff --git a/tests/ir/scalar-truncate.slang.expected.txt b/tests/ir/scalar-truncate.slang.expected.txt new file mode 100644 index 000000000..edaa32088 --- /dev/null +++ b/tests/ir/scalar-truncate.slang.expected.txt @@ -0,0 +1,4 @@ +7530 +FFFFF2C0 +0 +0 |
