Implement remaining bit twiddling operations

This commit is contained in:
baldurk
2020-04-16 18:41:58 +01:00
parent a725a4e278
commit f2cb1ddc53
6 changed files with 271 additions and 0 deletions
@@ -26,6 +26,7 @@
#include <math.h>
#include <time.h>
#include "common/formatting.h"
#include "os/os_specific.h"
#include "spirv_op_helpers.h"
static bool ContainsNaNInf(const ShaderVariable &val)
@@ -1202,6 +1203,85 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
//
//////////////////////////////////////////////////////////////////////////////
case Op::BitCount:
{
OpBitCount bitwise(it);
ShaderVariable var = GetSrc(bitwise.base);
for(uint8_t c = 0; c < var.columns; c++)
var.value.uv[c] = Bits::CountOnes(var.value.uv[c]);
SetDst(bitwise.result, var);
break;
}
case Op::BitReverse:
{
OpBitReverse bitwise(it);
ShaderVariable var = GetSrc(bitwise.base);
for(uint8_t c = 0; c < var.columns; c++)
{
uint32_t u = var.value.uv[c];
var.value.uv[c] = 0;
for(uint8_t b = 0; b < 32; b++)
{
uint32_t bit = u & (1u << b);
var.value.uv[c] |= bit << (31 - b);
}
}
SetDst(bitwise.result, var);
break;
}
case Op::BitFieldUExtract:
case Op::BitFieldSExtract:
{
OpBitFieldUExtract bitwise(it);
ShaderVariable var = GetSrc(bitwise.base);
ShaderVariable offset = GetSrc(bitwise.offset);
ShaderVariable count = GetSrc(bitwise.count);
for(uint8_t c = 0; c < var.columns; c++)
{
const uint32_t mask = (1u << count.value.uv[c]) - 1;
var.value.uv[c] >>= offset.value.uv[c];
var.value.uv[c] &= (1u << count.value.uv[c]) - 1;
if(opdata.op == Op::BitFieldSExtract)
{
uint32_t topbit = (mask + 1u) >> 1u;
if(var.value.uv[c] & topbit)
var.value.uv[c] |= (0xffffffffu ^ mask);
}
}
SetDst(bitwise.result, var);
break;
}
case Op::BitFieldInsert:
{
OpBitFieldInsert bitwise(it);
ShaderVariable var = GetSrc(bitwise.base);
ShaderVariable insert = GetSrc(bitwise.insert);
ShaderVariable offset = GetSrc(bitwise.offset);
ShaderVariable count = GetSrc(bitwise.count);
for(uint8_t c = 0; c < var.columns; c++)
{
const uint32_t mask = (1u << count.value.uv[c]) - 1;
var.value.uv[c] &= ~(mask << offset.value.uv[c]);
var.value.uv[c] |= (insert.value.uv[c] & mask) << offset.value.uv[c];
}
SetDst(bitwise.result, var);
break;
}
case Op::BitwiseOr:
case Op::BitwiseAnd:
case Op::BitwiseXor:
@@ -25,6 +25,7 @@
#include "spirv_debug.h"
#include <math.h>
#include "maths/matrix.h"
#include "os/os_specific.h"
namespace rdcspv
{
@@ -585,6 +586,51 @@ ShaderVariable Reflect(ThreadState &state, uint32_t, const rdcarray<Id> &params)
return N;
}
ShaderVariable FindILsb(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable x = state.GetSrc(params[0]);
for(uint8_t c = 0; c < x.columns; c++)
x.value.iv[c] = x.value.uv[c] == 0 ? -1 : Bits::CountTrailingZeroes(x.value.uv[c]);
return x;
}
ShaderVariable FindSMsb(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable x = state.GetSrc(params[0]);
for(uint8_t c = 0; c < x.columns; c++)
{
if(x.value.iv[c] == 0 || x.value.iv[c] == -1)
x.value.iv[c] = -1;
else if(x.value.iv[c] >= 0)
x.value.uv[c] = 31 - Bits::CountLeadingZeroes(x.value.uv[c]);
else
x.value.uv[c] = 31 - Bits::CountLeadingZeroes(~x.value.uv[c]);
}
return x;
}
ShaderVariable FindUMsb(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable x = state.GetSrc(params[0]);
for(uint8_t c = 0; c < x.columns; c++)
{
x.value.iv[c] = x.value.iv[c] == 0 ? -1 : 31 - Bits::CountLeadingZeroes(x.value.uv[c]);
}
return x;
}
static float GLSLNMax(float x, float y)
{
const bool xnan = isnan(x);
@@ -711,6 +757,9 @@ void ConfigureGLSLStd450(ExtInstDispatcher &extinst)
EXT(Cross);
EXT(FaceForward);
EXT(Reflect);
EXT(FindILsb);
EXT(FindSMsb);
EXT(FindUMsb);
EXT(NMin);
EXT(NMax);
EXT(NClamp);
+56
View File
@@ -258,6 +258,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 32);
CHECK(Bits::CountTrailingZeroes(val) == 32);
CHECK(Bits::CountOnes(val) == 0);
}
val = 1;
@@ -265,6 +267,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 31);
CHECK(Bits::CountTrailingZeroes(val) == 0);
CHECK(Bits::CountOnes(val) == 1);
}
val <<= 1;
@@ -272,6 +276,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 30);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 1);
}
val <<= 4;
@@ -279,6 +285,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 26);
CHECK(Bits::CountTrailingZeroes(val) == 5);
CHECK(Bits::CountOnes(val) == 1);
}
val++;
@@ -286,6 +294,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 26);
CHECK(Bits::CountTrailingZeroes(val) == 0);
CHECK(Bits::CountOnes(val) == 2);
}
val += 5;
@@ -293,6 +303,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 26);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 3);
}
val += 1000;
@@ -300,6 +312,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 21);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 4);
}
val *= 3;
@@ -307,6 +321,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 20);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 5);
}
val *= 200000;
@@ -314,6 +330,17 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 2);
CHECK(Bits::CountTrailingZeroes(val) == 7);
CHECK(Bits::CountOnes(val) == 12);
}
val |= 0xFFFFFFFFu;
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 0);
CHECK(Bits::CountTrailingZeroes(val) == 0);
CHECK(Bits::CountOnes(val) == 32);
}
};
@@ -325,6 +352,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 64);
CHECK(Bits::CountTrailingZeroes(val) == 64);
CHECK(Bits::CountOnes(val) == 0);
}
val = 1;
@@ -332,6 +361,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 63);
CHECK(Bits::CountTrailingZeroes(val) == 0);
CHECK(Bits::CountOnes(val) == 1);
}
val <<= 1;
@@ -339,6 +370,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 62);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 1);
}
val <<= 4;
@@ -346,6 +379,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 58);
CHECK(Bits::CountTrailingZeroes(val) == 5);
CHECK(Bits::CountOnes(val) == 1);
}
val++;
@@ -353,6 +388,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 58);
CHECK(Bits::CountTrailingZeroes(val) == 0);
CHECK(Bits::CountOnes(val) == 2);
}
val += 5;
@@ -360,6 +397,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 58);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 3);
}
val += 1000;
@@ -367,6 +406,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 53);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 4);
}
val *= 3;
@@ -374,6 +415,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 52);
CHECK(Bits::CountTrailingZeroes(val) == 1);
CHECK(Bits::CountOnes(val) == 5);
}
val *= 200000;
@@ -381,6 +424,8 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 34);
CHECK(Bits::CountTrailingZeroes(val) == 7);
CHECK(Bits::CountOnes(val) == 12);
}
val *= 1000000;
@@ -388,6 +433,17 @@ TEST_CASE("Test OS-specific functions", "[osspecific]")
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 14);
CHECK(Bits::CountTrailingZeroes(val) == 13);
CHECK(Bits::CountOnes(val) == 19);
}
val |= 0xFFFFFFFFFFFFFFFFull;
{
INFO("val is " << val);
CHECK(Bits::CountLeadingZeroes(val) == 0);
CHECK(Bits::CountTrailingZeroes(val) == 0);
CHECK(Bits::CountOnes(val) == 64);
}
};
#endif
+24
View File
@@ -120,4 +120,28 @@ inline uint64_t CountLeadingZeroes(uint64_t value)
return value == 0 ? 64 : __builtin_clzl(value);
}
#endif
inline uint32_t CountTrailingZeroes(uint32_t value)
{
return value == 0 ? 32 : __builtin_ctz(value);
}
#if ENABLED(RDOC_X64)
inline uint64_t CountTrailingZeroes(uint64_t value)
{
return value == 0 ? 64 : __builtin_ctzl(value);
}
#endif
inline uint32_t CountOnes(uint32_t value)
{
return __builtin_popcount(value);
}
#if ENABLED(RDOC_X64)
inline uint64_t CountOnes(uint64_t value)
{
return __builtin_popcountl(value);
}
#endif
};
+28
View File
@@ -83,4 +83,32 @@ inline uint64_t CountLeadingZeroes(uint64_t value)
return (result == TRUE) ? (index ^ 63) : 64;
}
#endif
inline uint32_t CountTrailingZeroes(uint32_t value)
{
DWORD index;
BOOLEAN result = _BitScanForward(&index, value);
return (result == TRUE) ? index : 32;
}
#if ENABLED(RDOC_X64)
inline uint64_t CountTrailingZeroes(uint64_t value)
{
DWORD index;
BOOLEAN result = _BitScanForward64(&index, value);
return (result == TRUE) ? index : 64;
}
#endif
inline uint32_t CountOnes(uint32_t value)
{
return __popcnt(value);
}
#if ENABLED(RDOC_X64)
inline uint64_t CountOnes(uint64_t value)
{
return __popcnt64(value);
}
#endif
};
@@ -847,6 +847,40 @@ void main()
}
)EOSHADER"
R"EOSHADER(
case 102:
{
uint a = zerou + 0x0dadbeef;
int b = zeroi + 0x0dadbeef;
Color = vec4(float(findLSB(a)), float(findLSB(b)), float(findMSB(a)), float(findMSB(b)));
break;
}
case 103:
{
int a = zeroi - 0x0dadbeef;
Color = vec4(float(findLSB(a)), float(findLSB(zeroi)), float(findMSB(a)), float(findMSB(zeroi)));
break;
}
case 104:
{
uint a = zerou + 0x44b82a24;
int b = zeroi + 0x44b82a24;
Color = vec4(float(bitCount(a)), float(bitCount(b)), uintBitsToFloat(bitfieldReverse(a)), intBitsToFloat(bitfieldReverse(b)));
break;
}
case 105:
{
uint a = zerou + 0x44b82a24;
int b = zeroi + 0x44b82a24;
uint af = zerou+0xffffffff;
int bf = zeroi-1;
Color = vec4(float(bitfieldExtract(a, 4, 5)), float(bitfieldExtract(b, 4, 5)),
uintBitsToFloat(bitfieldInsert(a, af, 4, 5)), intBitsToFloat(bitfieldInsert(b, bf, 4, 5)));
break;
}
default: break;
}
}