diff --git a/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h b/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h index 750dc7e23..ff92cfb54 100644 --- a/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h +++ b/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h @@ -350,9 +350,9 @@ void EmitBitwiseAnd64(EmitContext& ctx, const Operands& dest, const Operands& op void EmitBitwiseOr32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); void EmitBitwiseOr64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); void EmitBitwiseXor32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); -void EmitBitFieldInsert(EmitContext& ctx); -void EmitBitFieldSExtract(EmitContext& ctx); -void EmitBitFieldUExtract(EmitContext& ctx); +void EmitBitFieldInsert(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& insert, const Operands& offset, const Operands& count); +void EmitBitFieldSExtract(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& offset, const Operands& count); +void EmitBitFieldUExtract(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& offset, const Operands& count); void EmitBitReverse32(EmitContext& ctx); void EmitBitCount32(EmitContext& ctx); void EmitBitCount64(EmitContext& ctx); diff --git a/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp b/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp index 5c9d1c4e9..2a930951b 100644 --- a/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp +++ b/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp @@ -300,16 +300,70 @@ void EmitBitwiseXor32(EmitContext& ctx, const Operands& dest, const Operands& op MovGP(ctx, dest[0], tmp); } -void EmitBitFieldInsert(EmitContext& ctx) { - throw NotImplementedException("BitFieldInsert"); +void EmitBitFieldInsert(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& insert, const Operands& offset, const Operands& count) { + bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]); + OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg().cvt32() : dest[0]; + Reg mask = ctx.TempGPReg().cvt32(); + Reg tmp2 = ctx.TempGPReg().cvt32(); + MovGP(ctx, tmp, base[0]); + MovGP(ctx, cl, count[0]); + MovGP(ctx, tmp2, insert[0]); + ctx.Code().mov(mask, 1); + ctx.Code().shl(mask, cl); + ctx.Code().sub(mask, 1); + MovGP(ctx, cl, offset[0]); + ctx.Code().shl(mask, cl); + ctx.Code().shl(tmp2, cl); + ctx.Code().and_(tmp2, mask); + ctx.Code().not_(mask); + ctx.Code().and_(tmp.Op(), mask); + ctx.Code().or_(tmp.Op(), tmp2); + MovGP(ctx, dest[0], tmp); + if (rcx_saved) { + EmitRestoreRegTemp(ctx, rcx); + } } -void EmitBitFieldSExtract(EmitContext& ctx) { - throw NotImplementedException("BitFieldSExtract"); +void EmitBitFieldSExtract(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& offset, const Operands& count) { + bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]); + OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg().cvt32() : dest[0]; + Reg mask = ctx.TempGPReg().cvt32(); + MovGP(ctx, tmp, base[0]); + MovGP(ctx, cl, count[0]); + ctx.Code().mov(mask, 1); + ctx.Code().shl(mask, cl); + ctx.Code().sub(mask, 1); + MovGP(ctx, cl, offset[0]); + ctx.Code().shl(mask, cl); + ctx.Code().and_(tmp.Op(), mask); + ctx.Code().shr(tmp.Op(), cl); + ctx.Code().mov(ecx, 0x20); + ctx.Code().sub(ecx, count[0].Op()); + ctx.Code().shl(tmp.Op(), cl); + ctx.Code().sar(tmp.Op(), cl); + MovGP(ctx, dest[0], tmp); + if (rcx_saved) { + EmitRestoreRegTemp(ctx, rcx); + } } -void EmitBitFieldUExtract(EmitContext& ctx) { - throw NotImplementedException("BitFieldUExtract"); +void EmitBitFieldUExtract(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& offset, const Operands& count) { + bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]); + OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg().cvt32() : dest[0]; + Reg mask = ctx.TempGPReg().cvt32(); + MovGP(ctx, tmp, base[0]); + MovGP(ctx, cl, count[0]); + ctx.Code().mov(mask, 1); + ctx.Code().shl(mask, cl); + ctx.Code().sub(mask, 1); + MovGP(ctx, cl, offset[0]); + ctx.Code().shl(mask, cl); + ctx.Code().and_(tmp.Op(), mask); + ctx.Code().shr(tmp.Op(), cl); + MovGP(ctx, dest[0], tmp); + if (rcx_saved) { + EmitRestoreRegTemp(ctx, rcx); + } } void EmitBitReverse32(EmitContext& ctx) {