Skip to content

Commit fff3bf9

Browse files
authored
s_flbit_i32_b64 (shadps4-emu#3033)
* s_flbit_i32_b64 * Split FindUMsb64 into two 32bit ops
1 parent 43bf4ed commit fff3bf9

File tree

7 files changed

+40
-3
lines changed

7 files changed

+40
-3
lines changed

src/shader_recompiler/backend/spirv/emit_spirv_instructions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ Id EmitBitCount64(EmitContext& ctx, Id value);
372372
Id EmitBitwiseNot32(EmitContext& ctx, Id value);
373373
Id EmitFindSMsb32(EmitContext& ctx, Id value);
374374
Id EmitFindUMsb32(EmitContext& ctx, Id value);
375+
Id EmitFindUMsb64(EmitContext& ctx, Id value);
375376
Id EmitFindILsb32(EmitContext& ctx, Id value);
376377
Id EmitFindILsb64(EmitContext& ctx, Id value);
377378
Id EmitSMin32(EmitContext& ctx, Id a, Id b);

src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,20 @@ Id EmitFindUMsb32(EmitContext& ctx, Id value) {
229229
return ctx.OpFindUMsb(ctx.U32[1], value);
230230
}
231231

232+
Id EmitFindUMsb64(EmitContext& ctx, Id value) {
233+
// Vulkan restricts some bitwise operations to 32-bit only, so decompose into
234+
// two 32-bit values and select the correct result.
235+
const Id unpacked{ctx.OpBitcast(ctx.U32[2], value)};
236+
const Id hi{ctx.OpCompositeExtract(ctx.U32[1], unpacked, 1U)};
237+
const Id lo{ctx.OpCompositeExtract(ctx.U32[1], unpacked, 0U)};
238+
const Id hi_msb{ctx.OpFindUMsb(ctx.U32[1], hi)};
239+
const Id lo_msb{ctx.OpFindUMsb(ctx.U32[1], lo)};
240+
const Id found_hi{ctx.OpINotEqual(ctx.U1[1], hi_msb, ctx.ConstU32(u32(-1)))};
241+
const Id shifted_hi{ctx.OpIAdd(ctx.U32[1], hi_msb, ctx.ConstU32(32u))};
242+
// value == 0 case is checked in IREmitter
243+
return ctx.OpSelect(ctx.U32[1], found_hi, shifted_hi, lo_msb);
244+
}
245+
232246
Id EmitFindILsb32(EmitContext& ctx, Id value) {
233247
return ctx.OpFindILsb(ctx.U32[1], value);
234248
}

src/shader_recompiler/frontend/translate/scalar_alu.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ void Translator::EmitScalarAlu(const GcnInst& inst) {
114114
return S_FF1_I32_B64(inst);
115115
case Opcode::S_FLBIT_I32_B32:
116116
return S_FLBIT_I32_B32(inst);
117+
case Opcode::S_FLBIT_I32_B64:
118+
return S_FLBIT_I32_B64(inst);
117119
case Opcode::S_BITSET0_B32:
118120
return S_BITSET_B32(inst, 0);
119121
case Opcode::S_BITSET1_B32:
@@ -686,6 +688,17 @@ void Translator::S_FLBIT_I32_B32(const GcnInst& inst) {
686688
SetDst(inst.dst[0], IR::U32{ir.Select(cond, pos_from_left, ir.Imm32(~0U))});
687689
}
688690

691+
void Translator::S_FLBIT_I32_B64(const GcnInst& inst) {
692+
const IR::U64 src0{GetSrc64(inst.src[0])};
693+
// Gcn wants the MSB position counting from the left, but SPIR-V counts from the rightmost (LSB)
694+
// position
695+
const IR::U32 msb_pos = ir.FindUMsb(src0);
696+
const IR::U32 pos_from_left = ir.ISub(ir.Imm32(63), msb_pos);
697+
// Select 0xFFFFFFFF if src0 was 0
698+
const IR::U1 cond = ir.INotEqual(src0, ir.Imm64(u64(0u)));
699+
SetDst(inst.dst[0], IR::U32{ir.Select(cond, pos_from_left, ir.Imm32(~0U))});
700+
}
701+
689702
void Translator::S_BITSET_B32(const GcnInst& inst, u32 bit_value) {
690703
const IR::U32 old_value{GetSrc(inst.dst[0])};
691704
const IR::U32 offset{ir.BitFieldExtract(GetSrc(inst.src[0]), ir.Imm32(0U), ir.Imm32(5U))};

src/shader_recompiler/frontend/translate/translate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class Translator {
121121
void S_FF1_I32_B32(const GcnInst& inst);
122122
void S_FF1_I32_B64(const GcnInst& inst);
123123
void S_FLBIT_I32_B32(const GcnInst& inst);
124+
void S_FLBIT_I32_B64(const GcnInst& inst);
124125
void S_BITSET_B32(const GcnInst& inst, u32 bit_value);
125126
void S_GETPC_B64(u32 pc, const GcnInst& inst);
126127
void S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst);

src/shader_recompiler/ir/ir_emitter.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,8 +1546,15 @@ U32 IREmitter::FindSMsb(const U32& value) {
15461546
return Inst<U32>(Opcode::FindSMsb32, value);
15471547
}
15481548

1549-
U32 IREmitter::FindUMsb(const U32& value) {
1550-
return Inst<U32>(Opcode::FindUMsb32, value);
1549+
U32 IREmitter::FindUMsb(const U32U64& value) {
1550+
switch (value.Type()) {
1551+
case Type::U32:
1552+
return Inst<U32>(Opcode::FindUMsb32, value);
1553+
case Type::U64:
1554+
return Inst<U32>(Opcode::FindUMsb64, value);
1555+
default:
1556+
ThrowInvalidType(value.Type());
1557+
}
15511558
}
15521559

15531560
U32 IREmitter::FindILsb(const U32U64& value) {

src/shader_recompiler/ir/ir_emitter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ class IREmitter {
266266
[[nodiscard]] U32 BitwiseNot(const U32& value);
267267

268268
[[nodiscard]] U32 FindSMsb(const U32& value);
269-
[[nodiscard]] U32 FindUMsb(const U32& value);
269+
[[nodiscard]] U32 FindUMsb(const U32U64& value);
270270
[[nodiscard]] U32 FindILsb(const U32U64& value);
271271
[[nodiscard]] U32 SMin(const U32& a, const U32& b);
272272
[[nodiscard]] U32 UMin(const U32& a, const U32& b);

src/shader_recompiler/ir/opcodes.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ OPCODE(BitwiseNot32, U32, U32,
349349

350350
OPCODE(FindSMsb32, U32, U32, )
351351
OPCODE(FindUMsb32, U32, U32, )
352+
OPCODE(FindUMsb64, U32, U64, )
352353
OPCODE(FindILsb32, U32, U32, )
353354
OPCODE(FindILsb64, U32, U64, )
354355
OPCODE(SMin32, U32, U32, U32, )

0 commit comments

Comments
 (0)