code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "shader_recompiler/frontend/maxwell/translate/impl/half_floating_point_helper.h"

namespace Shader::Maxwell {
namespace {
void HMUL2(TranslatorVisitor& v, u64 insn, Merge merge, bool sat, bool abs_a, bool neg_a,
           Swizzle swizzle_a, bool abs_b, bool neg_b, Swizzle swizzle_b, const IR::U32& src_b,
           HalfPrecision precision) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_a;
    } const hmul2{insn};

    auto [lhs_a, rhs_a]{Extract(v.ir, v.X(hmul2.src_a), swizzle_a)};
    auto [lhs_b, rhs_b]{Extract(v.ir, src_b, swizzle_b)};
    const bool promotion{lhs_a.Type() != lhs_b.Type()};
    if (promotion) {
        if (lhs_a.Type() == IR::Type::F16) {
            lhs_a = v.ir.FPConvert(32, lhs_a);
            rhs_a = v.ir.FPConvert(32, rhs_a);
        }
        if (lhs_b.Type() == IR::Type::F16) {
            lhs_b = v.ir.FPConvert(32, lhs_b);
            rhs_b = v.ir.FPConvert(32, rhs_b);
        }
    }
    lhs_a = v.ir.FPAbsNeg(lhs_a, abs_a, neg_a);
    rhs_a = v.ir.FPAbsNeg(rhs_a, abs_a, neg_a);

    lhs_b = v.ir.FPAbsNeg(lhs_b, abs_b, neg_b);
    rhs_b = v.ir.FPAbsNeg(rhs_b, abs_b, neg_b);

    const IR::FpControl fp_control{
        .no_contraction = true,
        .rounding = IR::FpRounding::DontCare,
        .fmz_mode = HalfPrecision2FmzMode(precision),
    };
    IR::F16F32F64 lhs{v.ir.FPMul(lhs_a, lhs_b, fp_control)};
    IR::F16F32F64 rhs{v.ir.FPMul(rhs_a, rhs_b, fp_control)};
    if (precision == HalfPrecision::FMZ && !sat) {
        // Do not implement FMZ if SAT is enabled, as it does the logic for us.
        // On D3D9 mode, anything * 0 is zero, even NAN and infinity
        const IR::F32 zero{v.ir.Imm32(0.0f)};
        const IR::U1 lhs_zero_a{v.ir.FPEqual(lhs_a, zero)};
        const IR::U1 lhs_zero_b{v.ir.FPEqual(lhs_b, zero)};
        const IR::U1 lhs_any_zero{v.ir.LogicalOr(lhs_zero_a, lhs_zero_b)};
        lhs = IR::F16F32F64{v.ir.Select(lhs_any_zero, zero, lhs)};

        const IR::U1 rhs_zero_a{v.ir.FPEqual(rhs_a, zero)};
        const IR::U1 rhs_zero_b{v.ir.FPEqual(rhs_b, zero)};
        const IR::U1 rhs_any_zero{v.ir.LogicalOr(rhs_zero_a, rhs_zero_b)};
        rhs = IR::F16F32F64{v.ir.Select(rhs_any_zero, zero, rhs)};
    }
    if (sat) {
        lhs = v.ir.FPSaturate(lhs);
        rhs = v.ir.FPSaturate(rhs);
    }
    if (promotion) {
        lhs = v.ir.FPConvert(16, lhs);
        rhs = v.ir.FPConvert(16, rhs);
    }
    v.X(hmul2.dest_reg, MergeResult(v.ir, hmul2.dest_reg, lhs, rhs, merge));
}

void HMUL2(TranslatorVisitor& v, u64 insn, bool sat, bool abs_a, bool neg_a, bool abs_b, bool neg_b,
           Swizzle swizzle_b, const IR::U32& src_b) {
    union {
        u64 raw;
        BitField<49, 2, Merge> merge;
        BitField<47, 2, Swizzle> swizzle_a;
        BitField<39, 2, HalfPrecision> precision;
    } const hmul2{insn};

    HMUL2(v, insn, hmul2.merge, sat, abs_a, neg_a, hmul2.swizzle_a, abs_b, neg_b, swizzle_b, src_b,
          hmul2.precision);
}
} // Anonymous namespace

void TranslatorVisitor::HMUL2_reg(u64 insn) {
    union {
        u64 raw;
        BitField<32, 1, u64> sat;
        BitField<31, 1, u64> neg_b;
        BitField<30, 1, u64> abs_b;
        BitField<44, 1, u64> abs_a;
        BitField<28, 2, Swizzle> swizzle_b;
    } const hmul2{insn};

    HMUL2(*this, insn, hmul2.sat != 0, hmul2.abs_a != 0, false, hmul2.abs_b != 0, hmul2.neg_b != 0,
          hmul2.swizzle_b, GetReg20(insn));
}

void TranslatorVisitor::HMUL2_cbuf(u64 insn) {
    union {
        u64 raw;
        BitField<52, 1, u64> sat;
        BitField<54, 1, u64> abs_b;
        BitField<43, 1, u64> neg_a;
        BitField<44, 1, u64> abs_a;
    } const hmul2{insn};

    HMUL2(*this, insn, hmul2.sat != 0, hmul2.abs_a != 0, hmul2.neg_a != 0, hmul2.abs_b != 0, false,
          Swizzle::F32, GetCbuf(insn));
}

void TranslatorVisitor::HMUL2_imm(u64 insn) {
    union {
        u64 raw;
        BitField<52, 1, u64> sat;
        BitField<56, 1, u64> neg_high;
        BitField<30, 9, u64> high;
        BitField<29, 1, u64> neg_low;
        BitField<20, 9, u64> low;
        BitField<43, 1, u64> neg_a;
        BitField<44, 1, u64> abs_a;
    } const hmul2{insn};

    const u32 imm{
        static_cast<u32>(hmul2.low << 6) | static_cast<u32>((hmul2.neg_low != 0 ? 1 : 0) << 15) |
        static_cast<u32>(hmul2.high << 22) | static_cast<u32>((hmul2.neg_high != 0 ? 1 : 0) << 31)};
    HMUL2(*this, insn, hmul2.sat != 0, hmul2.abs_a != 0, hmul2.neg_a != 0, false, false,
          Swizzle::H1_H0, ir.Imm32(imm));
}

void TranslatorVisitor::HMUL2_32I(u64 insn) {
    union {
        u64 raw;
        BitField<55, 2, HalfPrecision> precision;
        BitField<52, 1, u64> sat;
        BitField<53, 2, Swizzle> swizzle_a;
        BitField<20, 32, u64> imm32;
    } const hmul2{insn};

    const u32 imm{static_cast<u32>(hmul2.imm32)};
    HMUL2(*this, insn, Merge::H1_H0, hmul2.sat != 0, false, false, hmul2.swizzle_a, false, false,
          Swizzle::H1_H0, ir.Imm32(imm), hmul2.precision);
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/half_floating_point_helper.h"

namespace Shader::Maxwell {
namespace {
void HSET2(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, bool bf, bool ftz, bool neg_b,
           bool abs_b, FPCompareOp compare_op, Swizzle swizzle_b) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_a_reg;
        BitField<39, 3, IR::Pred> pred;
        BitField<42, 1, u64> neg_pred;
        BitField<43, 1, u64> neg_a;
        BitField<45, 2, BooleanOp> bop;
        BitField<44, 1, u64> abs_a;
        BitField<47, 2, Swizzle> swizzle_a;
    } const hset2{insn};

    auto [lhs_a, rhs_a]{Extract(v.ir, v.X(hset2.src_a_reg), hset2.swizzle_a)};
    auto [lhs_b, rhs_b]{Extract(v.ir, src_b, swizzle_b)};

    if (lhs_a.Type() != lhs_b.Type()) {
        if (lhs_a.Type() == IR::Type::F16) {
            lhs_a = v.ir.FPConvert(32, lhs_a);
            rhs_a = v.ir.FPConvert(32, rhs_a);
        }
        if (lhs_b.Type() == IR::Type::F16) {
            lhs_b = v.ir.FPConvert(32, lhs_b);
            rhs_b = v.ir.FPConvert(32, rhs_b);
        }
    }

    lhs_a = v.ir.FPAbsNeg(lhs_a, hset2.abs_a != 0, hset2.neg_a != 0);
    rhs_a = v.ir.FPAbsNeg(rhs_a, hset2.abs_a != 0, hset2.neg_a != 0);

    lhs_b = v.ir.FPAbsNeg(lhs_b, abs_b, neg_b);
    rhs_b = v.ir.FPAbsNeg(rhs_b, abs_b, neg_b);

    const IR::FpControl control{
        .no_contraction = false,
        .rounding = IR::FpRounding::DontCare,
        .fmz_mode = (ftz ? IR::FmzMode::FTZ : IR::FmzMode::None),
    };

    IR::U1 pred{v.ir.GetPred(hset2.pred)};
    if (hset2.neg_pred != 0) {
        pred = v.ir.LogicalNot(pred);
    }
    const IR::U1 cmp_result_lhs{FloatingPointCompare(v.ir, lhs_a, lhs_b, compare_op, control)};
    const IR::U1 cmp_result_rhs{FloatingPointCompare(v.ir, rhs_a, rhs_b, compare_op, control)};
    const IR::U1 bop_result_lhs{PredicateCombine(v.ir, cmp_result_lhs, pred, hset2.bop)};
    const IR::U1 bop_result_rhs{PredicateCombine(v.ir, cmp_result_rhs, pred, hset2.bop)};

    const u32 true_value = bf ? 0x3c00 : 0xffff;
    const IR::U32 true_val_lhs{v.ir.Imm32(true_value)};
    const IR::U32 true_val_rhs{v.ir.Imm32(true_value << 16)};
    const IR::U32 fail_result{v.ir.Imm32(0)};
    const IR::U32 result_lhs{v.ir.Select(bop_result_lhs, true_val_lhs, fail_result)};
    const IR::U32 result_rhs{v.ir.Select(bop_result_rhs, true_val_rhs, fail_result)};

    v.X(hset2.dest_reg, IR::U32{v.ir.BitwiseOr(result_lhs, result_rhs)});
}
} // Anonymous namespace

void TranslatorVisitor::HSET2_reg(u64 insn) {
    union {
        u64 insn;
        BitField<30, 1, u64> abs_b;
        BitField<49, 1, u64> bf;
        BitField<31, 1, u64> neg_b;
        BitField<50, 1, u64> ftz;
        BitField<35, 4, FPCompareOp> compare_op;
        BitField<28, 2, Swizzle> swizzle_b;
    } const hset2{insn};

    HSET2(*this, insn, GetReg20(insn), hset2.bf != 0, hset2.ftz != 0, hset2.neg_b != 0,
          hset2.abs_b != 0, hset2.compare_op, hset2.swizzle_b);
}

void TranslatorVisitor::HSET2_cbuf(u64 insn) {
    union {
        u64 insn;
        BitField<53, 1, u64> bf;
        BitField<56, 1, u64> neg_b;
        BitField<54, 1, u64> ftz;
        BitField<49, 4, FPCompareOp> compare_op;
    } const hset2{insn};

    HSET2(*this, insn, GetCbuf(insn), hset2.bf != 0, hset2.ftz != 0, hset2.neg_b != 0, false,
          hset2.compare_op, Swizzle::F32);
}

void TranslatorVisitor::HSET2_imm(u64 insn) {
    union {
        u64 insn;
        BitField<53, 1, u64> bf;
        BitField<54, 1, u64> ftz;
        BitField<49, 4, FPCompareOp> compare_op;
        BitField<56, 1, u64> neg_high;
        BitField<30, 9, u64> high;
        BitField<29, 1, u64> neg_low;
        BitField<20, 9, u64> low;
    } const hset2{insn};

    const u32 imm{
        static_cast<u32>(hset2.low << 6) | static_cast<u32>((hset2.neg_low != 0 ? 1 : 0) << 15) |
        static_cast<u32>(hset2.high << 22) | static_cast<u32>((hset2.neg_high != 0 ? 1 : 0) << 31)};

    HSET2(*this, insn, ir.Imm32(imm), hset2.bf != 0, hset2.ftz != 0, false, false, hset2.compare_op,
          Swizzle::H1_H0);
}

} // namespace Shader::Maxwell

repo_name: litucks/torzu

license: mit


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/half_floating_point_helper.h"

namespace Shader::Maxwell {
namespace {
void HSETP2(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, bool neg_b, bool abs_b,
            Swizzle swizzle_b, FPCompareOp compare_op, bool h_and) {
    union {
        u64 insn;
        BitField<8, 8, IR::Reg> src_a_reg;
        BitField<3, 3, IR::Pred> dest_pred_a;
        BitField<0, 3, IR::Pred> dest_pred_b;
        BitField<39, 3, IR::Pred> pred;
        BitField<42, 1, u64> neg_pred;
        BitField<43, 1, u64> neg_a;
        BitField<45, 2, BooleanOp> bop;
        BitField<44, 1, u64> abs_a;
        BitField<6, 1, u64> ftz;
        BitField<47, 2, Swizzle> swizzle_a;
    } const hsetp2{insn};

    auto [lhs_a, rhs_a]{Extract(v.ir, v.X(hsetp2.src_a_reg), hsetp2.swizzle_a)};
    auto [lhs_b, rhs_b]{Extract(v.ir, src_b, swizzle_b)};

    if (lhs_a.Type() != lhs_b.Type()) {
        if (lhs_a.Type() == IR::Type::F16) {
            lhs_a = v.ir.FPConvert(32, lhs_a);
            rhs_a = v.ir.FPConvert(32, rhs_a);
        }
        if (lhs_b.Type() == IR::Type::F16) {
            lhs_b = v.ir.FPConvert(32, lhs_b);
            rhs_b = v.ir.FPConvert(32, rhs_b);
        }
    }

    lhs_a = v.ir.FPAbsNeg(lhs_a, hsetp2.abs_a != 0, hsetp2.neg_a != 0);
    rhs_a = v.ir.FPAbsNeg(rhs_a, hsetp2.abs_a != 0, hsetp2.neg_a != 0);

    lhs_b = v.ir.FPAbsNeg(lhs_b, abs_b, neg_b);
    rhs_b = v.ir.FPAbsNeg(rhs_b, abs_b, neg_b);

    const IR::FpControl control{
        .no_contraction = false,
        .rounding = IR::FpRounding::DontCare,
        .fmz_mode = (hsetp2.ftz != 0 ? IR::FmzMode::FTZ : IR::FmzMode::None),
    };

    IR::U1 pred{v.ir.GetPred(hsetp2.pred)};
    if (hsetp2.neg_pred != 0) {
        pred = v.ir.LogicalNot(pred);
    }
    const IR::U1 cmp_result_lhs{FloatingPointCompare(v.ir, lhs_a, lhs_b, compare_op, control)};
    const IR::U1 cmp_result_rhs{FloatingPointCompare(v.ir, rhs_a, rhs_b, compare_op, control)};
    const IR::U1 bop_result_lhs{PredicateCombine(v.ir, cmp_result_lhs, pred, hsetp2.bop)};
    const IR::U1 bop_result_rhs{PredicateCombine(v.ir, cmp_result_rhs, pred, hsetp2.bop)};

    if (h_and) {
        auto result = v.ir.LogicalAnd(bop_result_lhs, bop_result_rhs);
        v.ir.SetPred(hsetp2.dest_pred_a, result);
        v.ir.SetPred(hsetp2.dest_pred_b, v.ir.LogicalNot(result));
    } else {
        v.ir.SetPred(hsetp2.dest_pred_a, bop_result_lhs);
        v.ir.SetPred(hsetp2.dest_pred_b, bop_result_rhs);
    }
}
} // Anonymous namespace

void TranslatorVisitor::HSETP2_reg(u64 insn) {
    union {
        u64 insn;
        BitField<30, 1, u64> abs_b;
        BitField<49, 1, u64> h_and;
        BitField<31, 1, u64> neg_b;
        BitField<35, 4, FPCompareOp> compare_op;
        BitField<28, 2, Swizzle> swizzle_b;
    } const hsetp2{insn};
    HSETP2(*this, insn, GetReg20(insn), hsetp2.neg_b != 0, hsetp2.abs_b != 0, hsetp2.swizzle_b,
           hsetp2.compare_op, hsetp2.h_and != 0);
}

void TranslatorVisitor::HSETP2_cbuf(u64 insn) {
    union {
        u64 insn;
        BitField<53, 1, u64> h_and;
        BitField<54, 1, u64> abs_b;
        BitField<56, 1, u64> neg_b;
        BitField<49, 4, FPCompareOp> compare_op;
    } const hsetp2{insn};

    HSETP2(*this, insn, GetCbuf(insn), hsetp2.neg_b != 0, hsetp2.abs_b != 0, Swizzle::F32,
           hsetp2.compare_op, hsetp2.h_and != 0);
}

void TranslatorVisitor::HSETP2_imm(u64 insn) {
    union {
        u64 insn;
        BitField<53, 1, u64> h_and;
        BitField<54, 1, u64> ftz;
        BitField<49, 4, FPCompareOp> compare_op;
        BitField<56, 1, u64> neg_high;
        BitField<30, 9, u64> high;
        BitField<29, 1, u64> neg_low;
        BitField<20, 9, u64> low;
    } const hsetp2{insn};

    const u32 imm{static_cast<u32>(hsetp2.low << 6) |
                  static_cast<u32>((hsetp2.neg_low != 0 ? 1 : 0) << 15) |
                  static_cast<u32>(hsetp2.high << 22) |
                  static_cast<u32>((hsetp2.neg_high != 0 ? 1 : 0) << 31)};

    HSETP2(*this, insn, ir.Imm32(imm), false, false, Swizzle::H1_H0, hsetp2.compare_op,
           hsetp2.h_and != 0);
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
[[nodiscard]] IR::U32 CbufLowerBits(IR::IREmitter& ir, bool unaligned, const IR::U32& binding,
                                    u32 offset) {
    if (unaligned) {
        return ir.Imm32(0);
    }
    return ir.GetCbuf(binding, IR::U32{IR::Value{offset}});
}
} // Anonymous namespace

IR::U32 TranslatorVisitor::X(IR::Reg reg) {
    return ir.GetReg(reg);
}

IR::U64 TranslatorVisitor::L(IR::Reg reg) {
    if (!IR::IsAligned(reg, 2)) {
        throw NotImplementedException("Unaligned source register {}", reg);
    }
    return IR::U64{ir.PackUint2x32(ir.CompositeConstruct(X(reg), X(reg + 1)))};
}

IR::F32 TranslatorVisitor::F(IR::Reg reg) {
    return ir.BitCast<IR::F32>(X(reg));
}

IR::F64 TranslatorVisitor::D(IR::Reg reg) {
    if (!IR::IsAligned(reg, 2)) {
        throw NotImplementedException("Unaligned source register {}", reg);
    }
    return IR::F64{ir.PackDouble2x32(ir.CompositeConstruct(X(reg), X(reg + 1)))};
}

void TranslatorVisitor::X(IR::Reg dest_reg, const IR::U32& value) {
    ir.SetReg(dest_reg, value);
}

void TranslatorVisitor::L(IR::Reg dest_reg, const IR::U64& value) {
    if (!IR::IsAligned(dest_reg, 2)) {
        throw NotImplementedException("Unaligned destination register {}", dest_reg);
    }
    const IR::Value result{ir.UnpackUint2x32(value)};
    for (int i = 0; i < 2; i++) {
        X(dest_reg + i, IR::U32{ir.CompositeExtract(result, static_cast<size_t>(i))});
    }
}

void TranslatorVisitor::F(IR::Reg dest_reg, const IR::F32& value) {
    X(dest_reg, ir.BitCast<IR::U32>(value));
}

void TranslatorVisitor::D(IR::Reg dest_reg, const IR::F64& value) {
    if (!IR::IsAligned(dest_reg, 2)) {
        throw NotImplementedException("Unaligned destination register {}", dest_reg);
    }
    const IR::Value result{ir.UnpackDouble2x32(value)};
    for (int i = 0; i < 2; i++) {
        X(dest_reg + i, IR::U32{ir.CompositeExtract(result, static_cast<size_t>(i))});
    }
}

IR::U32 TranslatorVisitor::GetReg8(u64 insn) {
    union {
        u64 raw;
        BitField<8, 8, IR::Reg> index;
    } const reg{insn};
    return X(reg.index);
}

IR::U32 TranslatorVisitor::GetReg20(u64 insn) {
    union {
        u64 raw;
        BitField<20, 8, IR::Reg> index;
    } const reg{insn};
    return X(reg.index);
}

IR::U32 TranslatorVisitor::GetReg39(u64 insn) {
    union {
        u64 raw;
        BitField<39, 8, IR::Reg> index;
    } const reg{insn};
    return X(reg.index);
}

IR::F32 TranslatorVisitor::GetFloatReg8(u64 insn) {
    return ir.BitCast<IR::F32>(GetReg8(insn));
}

IR::F32 TranslatorVisitor::GetFloatReg20(u64 insn) {
    return ir.BitCast<IR::F32>(GetReg20(insn));
}

IR::F32 TranslatorVisitor::GetFloatReg39(u64 insn) {
    return ir.BitCast<IR::F32>(GetReg39(insn));
}

IR::F64 TranslatorVisitor::GetDoubleReg20(u64 insn) {
    union {
        u64 raw;
        BitField<20, 8, IR::Reg> index;
    } const reg{insn};
    return D(reg.index);
}

IR::F64 TranslatorVisitor::GetDoubleReg39(u64 insn) {
    union {
        u64 raw;
        BitField<39, 8, IR::Reg> index;
    } const reg{insn};
    return D(reg.index);
}

static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) {
    union {
        u64 raw;
        BitField<20, 14, u64> offset;
        BitField<34, 5, u64> binding;
    } const cbuf{insn};

    if (cbuf.binding >= 18) {
        throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding);
    }
    if (cbuf.offset >= 0x10'000) {
        throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset);
    }
    const IR::Value binding{static_cast<u32>(cbuf.binding)};
    const IR::Value byte_offset{static_cast<u32>(cbuf.offset) * 4};
    return {IR::U32{binding}, IR::U32{byte_offset}};
}

IR::U32 TranslatorVisitor::GetCbuf(u64 insn) {
    const auto [binding, byte_offset]{CbufAddr(insn)};
    return ir.GetCbuf(binding, byte_offset);
}

IR::F32 TranslatorVisitor::GetFloatCbuf(u64 insn) {
    const auto [binding, byte_offset]{CbufAddr(insn)};
    return ir.GetFloatCbuf(binding, byte_offset);
}

IR::F64 TranslatorVisitor::GetDoubleCbuf(u64 insn) {
    union {
        u64 raw;
        BitField<20, 1, u64> unaligned;
    } const cbuf{insn};

    const auto [binding, offset_value]{CbufAddr(insn)};
    const bool unaligned{cbuf.unaligned != 0};
    const u32 offset{offset_value.U32()};
    const IR::Value addr{unaligned ? offset | 4u : (offset & ~7u) | 4u};

    const IR::U32 value{ir.GetCbuf(binding, IR::U32{addr})};
    const IR::U32 lower_bits{CbufLowerBits(ir, unaligned, binding, offset)};
    return ir.PackDouble2x32(ir.CompositeConstruct(lower_bits, value));
}

IR::U64 TranslatorVisitor::GetPackedCbuf(u64 insn) {
    union {
        u64 raw;
        BitField<20, 1, u64> unaligned;
    } const cbuf{insn};

    if (cbuf.unaligned != 0) {
        throw NotImplementedException("Unaligned packed constant buffer read");
    }
    const auto [binding, lower_offset]{CbufAddr(insn)};
    const IR::U32 upper_offset{ir.Imm32(lower_offset.U32() + 4)};
    const IR::U32 lower_value{ir.GetCbuf(binding, lower_offset)};
    const IR::U32 upper_value{ir.GetCbuf(binding, upper_offset)};
    return ir.PackUint2x32(ir.CompositeConstruct(lower_value, upper_value));
}

IR::U32 TranslatorVisitor::GetImm20(u64 insn) {
    union {
        u64 raw;
        BitField<20, 19, u64> value;
        BitField<56, 1, u64> is_negative;
    } const imm{insn};

    if (imm.is_negative != 0) {
        const s64 raw{static_cast<s64>(imm.value)};
        return ir.Imm32(static_cast<s32>(-(1LL << 19) + raw));
    } else {
        return ir.Imm32(static_cast<u32>(imm.value));
    }
}

IR::F32 TranslatorVisitor::GetFloatImm20(u64 insn) {
    union {
        u64 raw;
        BitField<20, 19, u64> value;
        BitField<56, 1, u64> is_negative;
    } const imm{insn};
    const u32 sign_bit{static_cast<u32>(imm.is_negative != 0 ? (1ULL << 31) : 0)};
    const u32 value{static_cast<u32>(imm.value) << 12};
    return ir.Imm32(Common::BitCast<f32>(value | sign_bit));
}

IR::F64 TranslatorVisitor::GetDoubleImm20(u64 insn) {
    union {
        u64 raw;
        BitField<20, 19, u64> value;
        BitField<56, 1, u64> is_negative;
    } const imm{insn};
    const u64 sign_bit{imm.is_negative != 0 ? (1ULL << 63) : 0};
    const u64 value{imm.value << 44};
    return ir.Imm64(Common::BitCast<f64>(value | sign_bit));
}

IR::U64 TranslatorVisitor::GetPackedImm20(u64 insn) {
    const s64 value{GetImm20(insn).U32()};
    return ir.Imm64(static_cast<u64>(static_cast<s64>(value) << 32));
}

IR::U32 TranslatorVisitor::GetImm32(u64 insn) {
    union {
        u64 raw;
        BitField<20, 32, u64> value;
    } const imm{insn};
    return ir.Imm32(static_cast<u32>(imm.value));
}

IR::F32 TranslatorVisitor::GetFloatImm32(u64 insn) {
    union {
        u64 raw;
        BitField<20, 32, u64> value;
    } const imm{insn};
    return ir.Imm32(Common::BitCast<f32>(static_cast<u32>(imm.value)));
}

void TranslatorVisitor::SetZFlag(const IR::U1& value) {
    ir.SetZFlag(value);
}

void TranslatorVisitor::SetSFlag(const IR::U1& value) {
    ir.SetSFlag(value);
}

void TranslatorVisitor::SetCFlag(const IR::U1& value) {
    ir.SetCFlag(value);
}

void TranslatorVisitor::SetOFlag(const IR::U1& value) {
    ir.SetOFlag(value);
}

void TranslatorVisitor::ResetZero() {
    SetZFlag(ir.Imm1(false));
}

void TranslatorVisitor::ResetSFlag() {
    SetSFlag(ir.Imm1(false));
}

void TranslatorVisitor::ResetCFlag() {
    SetCFlag(ir.Imm1(false));
}

void TranslatorVisitor::ResetOFlag() {
    SetOFlag(ir.Imm1(false));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "shader_recompiler/environment.h"
#include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/frontend/maxwell/instruction.h"

namespace Shader::Maxwell {

enum class CompareOp : u64 {
    False,
    LessThan,
    Equal,
    LessThanEqual,
    GreaterThan,
    NotEqual,
    GreaterThanEqual,
    True,
};

enum class BooleanOp : u64 {
    AND,
    OR,
    XOR,
};

enum class PredicateOp : u64 {
    False,
    True,
    Zero,
    NonZero,
};

enum class FPCompareOp : u64 {
    F,
    LT,
    EQ,
    LE,
    GT,
    NE,
    GE,
    NUM,
    Nan,
    LTU,
    EQU,
    LEU,
    GTU,
    NEU,
    GEU,
    T,
};

class TranslatorVisitor {
public:
    explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {}

    Environment& env;
    IR::IREmitter ir;

    void AL2P(u64 insn);
    void ALD(u64 insn);
    void AST(u64 insn);
    void ATOM_cas(u64 insn);
    void ATOM(u64 insn);
    void ATOMS_cas(u64 insn);
    void ATOMS(u64 insn);
    void B2R(u64 insn);
    void BAR(u64 insn);
    void BFE_reg(u64 insn);
    void BFE_cbuf(u64 insn);
    void BFE_imm(u64 insn);
    void BFI_reg(u64 insn);
    void BFI_rc(u64 insn);
    void BFI_cr(u64 insn);
    void BFI_imm(u64 insn);
    void BPT(u64 insn);
    void BRA(u64 insn);
    void BRK(u64 insn);
    void BRX(u64 insn);
    void CAL();
    void CCTL(u64 insn);
    void CCTLL(u64 insn);
    void CONT(u64 insn);
    void CS2R(u64 insn);
    void CSET(u64 insn);
    void CSETP(u64 insn);
    void DADD_reg(u64 insn);
    void DADD_cbuf(u64 insn);
    void DADD_imm(u64 insn);
    void DEPBAR();
    void DFMA_reg(u64 insn);
    void DFMA_rc(u64 insn);
    void DFMA_cr(u64 insn);
    void DFMA_imm(u64 insn);
    void DMNMX_reg(u64 insn);
    void DMNMX_cbuf(u64 insn);
    void DMNMX_imm(u64 insn);
    void DMUL_reg(u64 insn);
    void DMUL_cbuf(u64 insn);
    void DMUL_imm(u64 insn);
    void DSET_reg(u64 insn);
    void DSET_cbuf(u64 insn);
    void DSET_imm(u64 insn);
    void DSETP_reg(u64 insn);
    void DSETP_cbuf(u64 insn);
    void DSETP_imm(u64 insn);
    void EXIT();
    void F2F_reg(u64 insn);
    void F2F_cbuf(u64 insn);
    void F2F_imm(u64 insn);
    void F2I_reg(u64 insn);
    void F2I_cbuf(u64 insn);
    void F2I_imm(u64 insn);
    void FADD_reg(u64 insn);
    void FADD_cbuf(u64 insn);
    void FADD_imm(u64 insn);
    void FADD32I(u64 insn);
    void FCHK_reg(u64 insn);
    void FCHK_cbuf(u64 insn);
    void FCHK_imm(u64 insn);
    void FCMP_reg(u64 insn);
    void FCMP_rc(u64 insn);
    void FCMP_cr(u64 insn);
    void FCMP_imm(u64 insn);
    void FFMA_reg(u64 insn);
    void FFMA_rc(u64 insn);
    void FFMA_cr(u64 insn);
    void FFMA_imm(u64 insn);
    void FFMA32I(u64 insn);
    void FLO_reg(u64 insn);
    void FLO_cbuf(u64 insn);
    void FLO_imm(u64 insn);
    void FMNMX_reg(u64 insn);
    void FMNMX_cbuf(u64 insn);
    void FMNMX_imm(u64 insn);
    void FMUL_reg(u64 insn);
    void FMUL_cbuf(u64 insn);
    void FMUL_imm(u64 insn);
    void FMUL32I(u64 insn);
    void FSET_reg(u64 insn);
    void FSET_cbuf(u64 insn);
    void FSET_imm(u64 insn);
    void FSETP_reg(u64 insn);
    void FSETP_cbuf(u64 insn);
    void FSETP_imm(u64 insn);
    void FSWZADD(u64 insn);
    void GETCRSPTR(u64 insn);
    void GETLMEMBASE(u64 insn);
    void HADD2_reg(u64 insn);
    void HADD2_cbuf(u64 insn);
    void HADD2_imm(u64 insn);
    void HADD2_32I(u64 insn);
    void HFMA2_reg(u64 insn);
    void HFMA2_rc(u64 insn);
    void HFMA2_cr(u64 insn);
    void HFMA2_imm(u64 insn);
    void HFMA2_32I(u64 insn);
    void HMUL2_reg(u64 insn);
    void HMUL2_cbuf(u64 insn);
    void HMUL2_imm(u64 insn);
    void HMUL2_32I(u64 insn);
    void HSET2_reg(u64 insn);
    void HSET2_cbuf(u64 insn);
    void HSET2_imm(u64 insn);
    void HSETP2_reg(u64 insn);
    void HSETP2_cbuf(u64 insn);
    void HSETP2_imm(u64 insn);
    void I2F_reg(u64 insn);
    void I2F_cbuf(u64 insn);
    void I2F_imm(u64 insn);
    void I2I_reg(u64 insn);
    void I2I_cbuf(u64 insn);
    void I2I_imm(u64 insn);
    void IADD_reg(u64 insn);
    void IADD_cbuf(u64 insn);
    void IADD_imm(u64 insn);
    void IADD3_reg(u64 insn);
    void IADD3_cbuf(u64 insn);
    void IADD3_imm(u64 insn);
    void IADD32I(u64 insn);
    void ICMP_reg(u64 insn);
    void ICMP_rc(u64 insn);
    void ICMP_cr(u64 insn);
    void ICMP_imm(u64 insn);
    void IDE(u64 insn);
    void IDP_reg(u64 insn);
    void IDP_imm(u64 insn);
    void IMAD_reg(u64 insn);
    void IMAD_rc(u64 insn);
    void IMAD_cr(u64 insn);
    void IMAD_imm(u64 insn);
    void IMAD32I(u64 insn);
    void IMADSP_reg(u64 insn);
    void IMADSP_rc(u64 insn);
    void IMADSP_cr(u64 insn);
    void IMADSP_imm(u64 insn);
    void IMNMX_reg(u64 insn);
    void IMNMX_cbuf(u64 insn);
    void IMNMX_imm(u64 insn);
    void IMUL_reg(u64 insn);
    void IMUL_cbuf(u64 insn);
    void IMUL_imm(u64 insn);
    void IMUL32I(u64 insn);
    void IPA(u64 insn);
    void ISBERD(u64 insn);
    void ISCADD_reg(u64 insn);
    void ISCADD_cbuf(u64 insn);
    void ISCADD_imm(u64 insn);
    void ISCADD32I(u64 insn);
    void ISET_reg(u64 insn);
    void ISET_cbuf(u64 insn);
    void ISET_imm(u64 insn);
    void ISETP_reg(u64 insn);
    void ISETP_cbuf(u64 insn);
    void ISETP_imm(u64 insn);
    void JCAL(u64 insn);
    void JMP(u64 insn);
    void JMX(u64 insn);
    void KIL();
    void LD(u64 insn);
    void LDC(u64 insn);
    void LDG(u64 insn);
    void LDL(u64 insn);
    void LDS(u64 insn);
    void LEA_hi_reg(u64 insn);
    void LEA_hi_cbuf(u64 insn);
    void LEA_lo_reg(u64 insn);
    void LEA_lo_cbuf(u64 insn);
    void LEA_lo_imm(u64 insn);
    void LEPC(u64 insn);
    void LONGJMP(u64 insn);
    void LOP_reg(u64 insn);
    void LOP_cbuf(u64 insn);
    void LOP_imm(u64 insn);
    void LOP3_reg(u64 insn);
    void LOP3_cbuf(u64 insn);
    void LOP3_imm(u64 insn);
    void LOP32I(u64 insn);
    void MEMBAR(u64 insn);
    void MOV_reg(u64 insn);
    void MOV_cbuf(u64 insn);
    void MOV_imm(u64 insn);
    void MOV32I(u64 insn);
    void MUFU(u64 insn);
    void NOP(u64 insn);
    void OUT_reg(u64 insn);
    void OUT_cbuf(u64 insn);
    void OUT_imm(u64 insn);
    void P2R_reg(u64 insn);
    void P2R_cbuf(u64 insn);
    void P2R_imm(u64 insn);
    void PBK();
    void PCNT();
    void PEXIT(u64 insn);
    void PIXLD(u64 insn);
    void PLONGJMP(u64 insn);
    void POPC_reg(u64 insn);
    void POPC_cbuf(u64 insn);
    void POPC_imm(u64 insn);
    void PRET(u64 insn);
    void PRMT_reg(u64 insn);
    void PRMT_rc(u64 insn);
    void PRMT_cr(u64 insn);
    void PRMT_imm(u64 insn);
    void PSET(u64 insn);
    void PSETP(u64 insn);
    void R2B(u64 insn);
    void R2P_reg(u64 insn);
    void R2P_cbuf(u64 insn);
    void R2P_imm(u64 insn);
    void RAM(u64 insn);
    void RED(u64 insn);
    void RET(u64 insn);
    void RRO_reg(u64 insn);
    void RRO_cbuf(u64 insn);
    void RRO_imm(u64 insn);
    void RTT(u64 insn);
    void S2R(u64 insn);
    void SAM(u64 insn);
    void SEL_reg(u64 insn);
    void SEL_cbuf(u64 insn);
    void SEL_imm(u64 insn);
    void SETCRSPTR(u64 insn);
    void SETLMEMBASE(u64 insn);
    void SHF_l_reg(u64 insn);
    void SHF_l_imm(u64 insn);
    void SHF_r_reg(u64 insn);
    void SHF_r_imm(u64 insn);
    void SHFL(u64 insn);
    void SHL_reg(u64 insn);
    void SHL_cbuf(u64 insn);
    void SHL_imm(u64 insn);
    void SHR_reg(u64 insn);
    void SHR_cbuf(u64 insn);
    void SHR_imm(u64 insn);
    void SSY();
    void ST(u64 insn);
    void STG(u64 insn);
    void STL(u64 insn);
    void STP(u64 insn);
    void STS(u64 insn);
    void SUATOM(u64 insn);
    void SUATOM_cas(u64 insn);
    void SULD(u64 insn);
    void SURED(u64 insn);
    void SUST(u64 insn);
    void SYNC(u64 insn);
    void TEX(u64 insn);
    void TEX_b(u64 insn);
    void TEXS(u64 insn);
    void TLD(u64 insn);
    void TLD_b(u64 insn);
    void TLD4(u64 insn);
    void TLD4_b(u64 insn);
    void TLD4S(u64 insn);
    void TLDS(u64 insn);
    void TMML(u64 insn);
    void TMML_b(u64 insn);
    void TXA(u64 insn);
    void TXD(u64 insn);
    void TXD_b(u64 insn);
    void TXQ(u64 insn);
    void TXQ_b(u64 insn);
    void VABSDIFF(u64 insn);
    void VABSDIFF4(u64 insn);
    void VADD(u64 insn);
    void VMAD(u64 insn);
    void VMNMX(u64 insn);
    void VOTE(u64 insn);
    void VOTE_vtg(u64 insn);
    void VSET(u64 insn);
    void VSETP(u64 insn);
    void VSHL(u64 insn);
    void VSHR(u64 insn);
    void XMAD_reg(u64 insn);
    void XMAD_rc(u64 insn);
    void XMAD_cr(u64 insn);
    void XMAD_imm(u64 insn);

    [[nodiscard]] IR::U32 X(IR::Reg reg);
    [[nodiscard]] IR::U64 L(IR::Reg reg);
    [[nodiscard]] IR::F32 F(IR::Reg reg);
    [[nodiscard]] IR::F64 D(IR::Reg reg);

    void X(IR::Reg dest_reg, const IR::U32& value);
    void L(IR::Reg dest_reg, const IR::U64& value);
    void F(IR::Reg dest_reg, const IR::F32& value);
    void D(IR::Reg dest_reg, const IR::F64& value);

    [[nodiscard]] IR::U32 GetReg8(u64 insn);
    [[nodiscard]] IR::U32 GetReg20(u64 insn);
    [[nodiscard]] IR::U32 GetReg39(u64 insn);
    [[nodiscard]] IR::F32 GetFloatReg8(u64 insn);
    [[nodiscard]] IR::F32 GetFloatReg20(u64 insn);
    [[nodiscard]] IR::F32 GetFloatReg39(u64 insn);
    [[nodiscard]] IR::F64 GetDoubleReg20(u64 insn);
    [[nodiscard]] IR::F64 GetDoubleReg39(u64 insn);

    [[nodiscard]] IR::U32 GetCbuf(u64 insn);
    [[nodiscard]] IR::F32 GetFloatCbuf(u64 insn);
    [[nodiscard]] IR::F64 GetDoubleCbuf(u64 insn);
    [[nodiscard]] IR::U64 GetPackedCbuf(u64 insn);

    [[nodiscard]] IR::U32 GetImm20(u64 insn);
    [[nodiscard]] IR::F32 GetFloatImm20(u64 insn);
    [[nodiscard]] IR::F64 GetDoubleImm20(u64 insn);
    [[nodiscard]] IR::U64 GetPackedImm20(u64 insn);

    [[nodiscard]] IR::U32 GetImm32(u64 insn);
    [[nodiscard]] IR::F32 GetFloatImm32(u64 insn);

    void SetZFlag(const IR::U1& value);
    void SetSFlag(const IR::U1& value);
    void SetCFlag(const IR::U1& value);
    void SetOFlag(const IR::U1& value);

    void ResetZero();
    void ResetSFlag();
    void ResetCFlag();
    void ResetOFlag();
};

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void IADD(TranslatorVisitor& v, u64 insn, const IR::U32 op_b, bool neg_a, bool po, bool sat, bool x,
          bool cc) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_a;
    } const iadd{insn};

    if (sat) {
        throw NotImplementedException("IADD SAT");
    }
    if (x && po) {
        throw NotImplementedException("IADD X+PO");
    }
    // Operand A is always read from here, negated if needed
    IR::U32 op_a{v.X(iadd.src_a)};
    if (neg_a) {
        op_a = v.ir.INeg(op_a);
    }
    // Add both operands
    IR::U32 result{v.ir.IAdd(op_a, op_b)};
    if (x) {
        const IR::U32 carry{v.ir.Select(v.ir.GetCFlag(), v.ir.Imm32(1), v.ir.Imm32(0))};
        result = v.ir.IAdd(result, carry);
    }
    if (po) {
        // .PO adds one to the result
        result = v.ir.IAdd(result, v.ir.Imm32(1));
    }
    if (cc) {
        // Store flags
        // TODO: Does this grab the result pre-PO or after?
        if (po) {
            throw NotImplementedException("IADD CC+PO");
        }
        // TODO: How does CC behave when X is set?
        if (x) {
            throw NotImplementedException("IADD X+CC");
        }
        v.SetZFlag(v.ir.GetZeroFromOp(result));
        v.SetSFlag(v.ir.GetSignFromOp(result));
        v.SetCFlag(v.ir.GetCarryFromOp(result));
        v.SetOFlag(v.ir.GetOverflowFromOp(result));
    }
    // Store result
    v.X(iadd.dest_reg, result);
}

void IADD(TranslatorVisitor& v, u64 insn, IR::U32 op_b) {
    union {
        u64 insn;
        BitField<43, 1, u64> x;
        BitField<47, 1, u64> cc;
        BitField<48, 2, u64> three_for_po;
        BitField<48, 1, u64> neg_b;
        BitField<49, 1, u64> neg_a;
        BitField<50, 1, u64> sat;
    } const iadd{insn};

    const bool po{iadd.three_for_po == 3};
    if (!po && iadd.neg_b != 0) {
        op_b = v.ir.INeg(op_b);
    }
    IADD(v, insn, op_b, iadd.neg_a != 0, po, iadd.sat != 0, iadd.x != 0, iadd.cc != 0);
}
} // Anonymous namespace

void TranslatorVisitor::IADD_reg(u64 insn) {
    IADD(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::IADD_cbuf(u64 insn) {
    IADD(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::IADD_imm(u64 insn) {
    IADD(*this, insn, GetImm20(insn));
}

void TranslatorVisitor::IADD32I(u64 insn) {
    union {
        u64 raw;
        BitField<52, 1, u64> cc;
        BitField<53, 1, u64> x;
        BitField<54, 1, u64> sat;
        BitField<55, 2, u64> three_for_po;
        BitField<56, 1, u64> neg_a;
    } const iadd32i{insn};

    const bool po{iadd32i.three_for_po == 3};
    const bool neg_a{!po && iadd32i.neg_a != 0};
    IADD(*this, insn, GetImm32(insn), neg_a, po, iadd32i.sat != 0, iadd32i.x != 0, iadd32i.cc != 0);
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class Shift : u64 {
    None,
    Right,
    Left,
};
enum class Half : u64 {
    All,
    Lower,
    Upper,
};

[[nodiscard]] IR::U32 IntegerHalf(IR::IREmitter& ir, const IR::U32& value, Half half) {
    constexpr bool is_signed{false};
    switch (half) {
    case Half::All:
        return value;
    case Half::Lower:
        return ir.BitFieldExtract(value, ir.Imm32(0), ir.Imm32(16), is_signed);
    case Half::Upper:
        return ir.BitFieldExtract(value, ir.Imm32(16), ir.Imm32(16), is_signed);
    }
    throw NotImplementedException("Invalid half");
}

[[nodiscard]] IR::U32 IntegerShift(IR::IREmitter& ir, const IR::U32& value, Shift shift) {
    switch (shift) {
    case Shift::None:
        return value;
    case Shift::Right: {
        // 33-bit RS IADD3 edge case
        const IR::U1 edge_case{ir.GetCarryFromOp(value)};
        const IR::U32 shifted{ir.ShiftRightLogical(value, ir.Imm32(16))};
        return IR::U32{ir.Select(edge_case, ir.IAdd(shifted, ir.Imm32(0x10000)), shifted)};
    }
    case Shift::Left:
        return ir.ShiftLeftLogical(value, ir.Imm32(16));
    }
    throw NotImplementedException("Invalid shift");
}

void IADD3(TranslatorVisitor& v, u64 insn, IR::U32 op_a, IR::U32 op_b, IR::U32 op_c,
           Shift shift = Shift::None) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<47, 1, u64> cc;
        BitField<48, 1, u64> x;
        BitField<49, 1, u64> neg_c;
        BitField<50, 1, u64> neg_b;
        BitField<51, 1, u64> neg_a;
    } iadd3{insn};

    if (iadd3.neg_a != 0) {
        op_a = v.ir.INeg(op_a);
    }
    if (iadd3.neg_b != 0) {
        op_b = v.ir.INeg(op_b);
    }
    if (iadd3.neg_c != 0) {
        op_c = v.ir.INeg(op_c);
    }
    IR::U32 lhs_1{v.ir.IAdd(op_a, op_b)};
    if (iadd3.x != 0) {
        // TODO: How does RS behave when X is set?
        if (shift == Shift::Right) {
            throw NotImplementedException("IADD3 X+RS");
        }
        const IR::U32 carry{v.ir.Select(v.ir.GetCFlag(), v.ir.Imm32(1), v.ir.Imm32(0))};
        lhs_1 = v.ir.IAdd(lhs_1, carry);
    }
    const IR::U32 lhs_2{IntegerShift(v.ir, lhs_1, shift)};
    const IR::U32 result{v.ir.IAdd(lhs_2, op_c)};

    v.X(iadd3.dest_reg, result);
    if (iadd3.cc != 0) {
        // TODO: How does CC behave when X is set?
        if (iadd3.x != 0) {
            throw NotImplementedException("IADD3 X+CC");
        }
        v.SetZFlag(v.ir.GetZeroFromOp(result));
        v.SetSFlag(v.ir.GetSignFromOp(result));
        v.SetCFlag(v.ir.GetCarryFromOp(result));
        const IR::U1 of_1{v.ir.ILessThan(lhs_1, op_a, false)};
        v.SetOFlag(v.ir.LogicalOr(v.ir.GetOverflowFromOp(result), of_1));
    }
}
} // Anonymous namespace

void TranslatorVisitor::IADD3_reg(u64 insn) {
    union {
        u64 insn;
        BitField<37, 2, Shift> shift;
        BitField<35, 2, Half> half_a;
        BitField<33, 2, Half> half_b;
        BitField<31, 2, Half> half_c;
    } const iadd3{insn};

    const auto op_a{IntegerHalf(ir, GetReg8(insn), iadd3.half_a)};
    const auto op_b{IntegerHalf(ir, GetReg20(insn), iadd3.half_b)};
    const auto op_c{IntegerHalf(ir, GetReg39(insn), iadd3.half_c)};
    IADD3(*this, insn, op_a, op_b, op_c, iadd3.shift);
}

void TranslatorVisitor::IADD3_cbuf(u64 insn) {
    IADD3(*this, insn, GetReg8(insn), GetCbuf(insn), GetReg39(insn));
}

void TranslatorVisitor::IADD3_imm(u64 insn) {
    IADD3(*this, insn, GetReg8(insn), GetImm20(insn), GetReg39(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void ICMP(TranslatorVisitor& v, u64 insn, const IR::U32& src_a, const IR::U32& operand) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_reg;
        BitField<48, 1, u64> is_signed;
        BitField<49, 3, CompareOp> compare_op;
    } const icmp{insn};

    const IR::U32 zero{v.ir.Imm32(0)};
    const bool is_signed{icmp.is_signed != 0};
    const IR::U1 cmp_result{IntegerCompare(v.ir, operand, zero, icmp.compare_op, is_signed)};

    const IR::U32 src_reg{v.X(icmp.src_reg)};
    const IR::U32 result{v.ir.Select(cmp_result, src_reg, src_a)};

    v.X(icmp.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::ICMP_reg(u64 insn) {
    ICMP(*this, insn, GetReg20(insn), GetReg39(insn));
}

void TranslatorVisitor::ICMP_rc(u64 insn) {
    ICMP(*this, insn, GetReg39(insn), GetCbuf(insn));
}

void TranslatorVisitor::ICMP_cr(u64 insn) {
    ICMP(*this, insn, GetCbuf(insn), GetReg39(insn));
}

void TranslatorVisitor::ICMP_imm(u64 insn) {
    ICMP(*this, insn, GetImm20(insn), GetReg39(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
IR::U1 IsetCompare(IR::IREmitter& ir, const IR::U32& operand_1, const IR::U32& operand_2,
                   CompareOp compare_op, bool is_signed, bool x) {
    return x ? ExtendedIntegerCompare(ir, operand_1, operand_2, compare_op, is_signed)
             : IntegerCompare(ir, operand_1, operand_2, compare_op, is_signed);
}

void ISET(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_reg;
        BitField<39, 3, IR::Pred> pred;
        BitField<42, 1, u64> neg_pred;
        BitField<43, 1, u64> x;
        BitField<44, 1, u64> bf;
        BitField<45, 2, BooleanOp> bop;
        BitField<47, 1, u64> cc;
        BitField<48, 1, u64> is_signed;
        BitField<49, 3, CompareOp> compare_op;
    } const iset{insn};

    const IR::U32 src_a{v.X(iset.src_reg)};
    const bool is_signed{iset.is_signed != 0};
    const IR::U32 zero{v.ir.Imm32(0)};
    const bool x{iset.x != 0};
    const IR::U1 cmp_result{IsetCompare(v.ir, src_a, src_b, iset.compare_op, is_signed, x)};

    IR::U1 pred{v.ir.GetPred(iset.pred)};
    if (iset.neg_pred != 0) {
        pred = v.ir.LogicalNot(pred);
    }
    const IR::U1 bop_result{PredicateCombine(v.ir, cmp_result, pred, iset.bop)};

    const IR::U32 one_mask{v.ir.Imm32(-1)};
    const IR::U32 fp_one{v.ir.Imm32(0x3f800000)};
    const IR::U32 pass_result{iset.bf == 0 ? one_mask : fp_one};
    const IR::U32 result{v.ir.Select(bop_result, pass_result, zero)};

    v.X(iset.dest_reg, result);
    if (iset.cc != 0) {
        if (x) {
            throw NotImplementedException("ISET.CC + X");
        }
        const IR::U1 is_zero{v.ir.IEqual(result, zero)};
        v.SetZFlag(is_zero);
        if (iset.bf != 0) {
            v.ResetSFlag();
        } else {
            v.SetSFlag(v.ir.LogicalNot(is_zero));
        }
        v.ResetCFlag();
        v.ResetOFlag();
    }
}
} // Anonymous namespace

void TranslatorVisitor::ISET_reg(u64 insn) {
    ISET(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::ISET_cbuf(u64 insn) {
    ISET(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::ISET_imm(u64 insn) {
    ISET(*this, insn, GetImm20(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class FloatFormat : u64 {
    F16 = 1,
    F32 = 2,
    F64 = 3,
};

enum class IntFormat : u64 {
    U8 = 0,
    U16 = 1,
    U32 = 2,
    U64 = 3,
};

union Encoding {
    u64 raw;
    BitField<0, 8, IR::Reg> dest_reg;
    BitField<8, 2, FloatFormat> float_format;
    BitField<10, 2, IntFormat> int_format;
    BitField<13, 1, u64> is_signed;
    BitField<39, 2, FpRounding> fp_rounding;
    BitField<41, 2, u64> selector;
    BitField<47, 1, u64> cc;
    BitField<45, 1, u64> neg;
    BitField<49, 1, u64> abs;
};

bool Is64(u64 insn) {
    return Encoding{insn}.int_format == IntFormat::U64;
}

int BitSize(FloatFormat format) {
    switch (format) {
    case FloatFormat::F16:
        return 16;
    case FloatFormat::F32:
        return 32;
    case FloatFormat::F64:
        return 64;
    }
    throw NotImplementedException("Invalid float format {}", format);
}

IR::U32 SmallAbs(TranslatorVisitor& v, const IR::U32& value, int bitsize) {
    const IR::U32 least_value{v.ir.Imm32(-(1 << (bitsize - 1)))};
    const IR::U32 mask{v.ir.ShiftRightArithmetic(value, v.ir.Imm32(bitsize - 1))};
    const IR::U32 absolute{v.ir.BitwiseXor(v.ir.IAdd(value, mask), mask)};
    const IR::U1 is_least{v.ir.IEqual(value, least_value)};
    return IR::U32{v.ir.Select(is_least, value, absolute)};
}

void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
    const Encoding i2f{insn};
    if (i2f.cc != 0) {
        throw NotImplementedException("I2F CC");
    }
    const bool is_signed{i2f.is_signed != 0};
    int src_bitsize{};
    switch (i2f.int_format) {
    case IntFormat::U8:
        src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8),
                                   v.ir.Imm32(8), is_signed);
        if (i2f.abs != 0) {
            src = SmallAbs(v, src, 8);
        }
        src_bitsize = 8;
        break;
    case IntFormat::U16:
        if (i2f.selector == 1 || i2f.selector == 3) {
            throw NotImplementedException("Invalid U16 selector {}", i2f.selector.Value());
        }
        src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8),
                                   v.ir.Imm32(16), is_signed);
        if (i2f.abs != 0) {
            src = SmallAbs(v, src, 16);
        }
        src_bitsize = 16;
        break;
    case IntFormat::U32:
    case IntFormat::U64:
        if (i2f.selector != 0) {
            throw NotImplementedException("Unexpected selector {}", i2f.selector.Value());
        }
        if (i2f.abs != 0 && is_signed) {
            src = v.ir.IAbs(src);
        }
        src_bitsize = i2f.int_format == IntFormat::U64 ? 64 : 32;
        break;
    }
    const int conversion_src_bitsize{i2f.int_format == IntFormat::U64 ? 64 : 32};
    const int dst_bitsize{BitSize(i2f.float_format)};
    const IR::FpControl fp_control{
        .no_contraction = false,
        .rounding = CastFpRounding(i2f.fp_rounding),
        .fmz_mode = IR::FmzMode::DontCare,
    };
    auto value{v.ir.ConvertIToF(static_cast<size_t>(dst_bitsize),
                                static_cast<size_t>(conversion_src_bitsize), is_signed, src,
                                fp_control)};
    if (i2f.neg != 0) {
        if (i2f.abs != 0 || !is_signed) {
            // We know the value is positive
            value = v.ir.FPNeg(value);
        } else {
            // Only negate if the input isn't the lowest value
            IR::U1 is_least;
            if (src_bitsize == 64) {
                is_least = v.ir.IEqual(src, v.ir.Imm64(std::numeric_limits<s64>::min()));
            } else if (src_bitsize == 32) {
                is_least = v.ir.IEqual(src, v.ir.Imm32(std::numeric_limits<s32>::min()));
            } else {
                const IR::U32 least_value{v.ir.Imm32(-(1 << (src_bitsize - 1)))};
                is_least = v.ir.IEqual(src, least_value);
            }
            value = IR::F16F32F64{v.ir.Select(is_least, value, v.ir.FPNeg(value))};
        }
    }
    switch (i2f.float_format) {
    case FloatFormat::F16: {
        const IR::F16 zero{v.ir.FPConvert(16, v.ir.Imm32(0.0f))};
        v.X(i2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(value, zero)));
        break;
    }
    case FloatFormat::F32:
        v.F(i2f.dest_reg, value);
        break;
    case FloatFormat::F64: {
        if (!IR::IsAligned(i2f.dest_reg, 2)) {
            throw NotImplementedException("Unaligned destination {}", i2f.dest_reg.Value());
        }
        const IR::Value vector{v.ir.UnpackDouble2x32(value)};
        for (int i = 0; i < 2; ++i) {
            v.X(i2f.dest_reg + i, IR::U32{v.ir.CompositeExtract(vector, static_cast<size_t>(i))});
        }
        break;
    }
    default:
        throw NotImplementedException("Invalid float format {}", i2f.float_format.Value());
    }
}
} // Anonymous namespace

void TranslatorVisitor::I2F_reg(u64 insn) {
    if (Is64(insn)) {
        union {
            u64 raw;
            BitField<20, 8, IR::Reg> reg;
        } const value{insn};
        const IR::Value regs{ir.CompositeConstruct(ir.GetReg(value.reg), ir.GetReg(value.reg + 1))};
        I2F(*this, insn, ir.PackUint2x32(regs));
    } else {
        I2F(*this, insn, GetReg20(insn));
    }
}

void TranslatorVisitor::I2F_cbuf(u64 insn) {
    if (Is64(insn)) {
        I2F(*this, insn, GetPackedCbuf(insn));
    } else {
        I2F(*this, insn, GetCbuf(insn));
    }
}

void TranslatorVisitor::I2F_imm(u64 insn) {
    if (Is64(insn)) {
        I2F(*this, insn, GetPackedImm20(insn));
    } else {
        I2F(*this, insn, GetImm20(insn));
    }
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class MaxShift : u64 {
    U32,
    Undefined,
    U64,
    S64,
};

IR::U64 PackedShift(IR::IREmitter& ir, const IR::U64& packed_int, const IR::U32& safe_shift,
                    bool right_shift, bool is_signed) {
    if (!right_shift) {
        return ir.ShiftLeftLogical(packed_int, safe_shift);
    }
    if (is_signed) {
        return ir.ShiftRightArithmetic(packed_int, safe_shift);
    }
    return ir.ShiftRightLogical(packed_int, safe_shift);
}

void SHF(TranslatorVisitor& v, u64 insn, const IR::U32& shift, const IR::U32& high_bits,
         bool right_shift) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> lo_bits_reg;
        BitField<37, 2, MaxShift> max_shift;
        BitField<47, 1, u64> cc;
        BitField<48, 2, u64> x_mode;
        BitField<50, 1, u64> wrap;
    } const shf{insn};

    if (shf.cc != 0) {
        throw NotImplementedException("SHF CC");
    }
    if (shf.x_mode != 0) {
        throw NotImplementedException("SHF X Mode");
    }
    if (shf.max_shift == MaxShift::Undefined) {
        throw NotImplementedException("SHF Use of undefined MaxShift value");
    }
    const IR::U32 low_bits{v.X(shf.lo_bits_reg)};
    const IR::U64 packed_int{v.ir.PackUint2x32(v.ir.CompositeConstruct(low_bits, high_bits))};
    const IR::U32 max_shift{shf.max_shift == MaxShift::U32 ? v.ir.Imm32(32) : v.ir.Imm32(63)};
    const IR::U32 safe_shift{shf.wrap != 0
                                 ? v.ir.BitwiseAnd(shift, v.ir.ISub(max_shift, v.ir.Imm32(1)))
                                 : v.ir.UMin(shift, max_shift)};

    const bool is_signed{shf.max_shift == MaxShift::S64};
    const IR::U64 shifted_value{PackedShift(v.ir, packed_int, safe_shift, right_shift, is_signed)};
    const IR::Value unpacked_value{v.ir.UnpackUint2x32(shifted_value)};

    const IR::U32 result{v.ir.CompositeExtract(unpacked_value, right_shift ? 0 : 1)};
    v.X(shf.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::SHF_l_reg(u64 insn) {
    SHF(*this, insn, GetReg20(insn), GetReg39(insn), false);
}

void TranslatorVisitor::SHF_l_imm(u64 insn) {
    SHF(*this, insn, GetImm20(insn), GetReg39(insn), false);
}

void TranslatorVisitor::SHF_r_reg(u64 insn) {
    SHF(*this, insn, GetReg20(insn), GetReg39(insn), true);
}

void TranslatorVisitor::SHF_r_imm(u64 insn) {
    SHF(*this, insn, GetImm20(insn), GetReg39(insn), true);
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void IMNMX(TranslatorVisitor& v, u64 insn, const IR::U32& op_b) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_reg;
        BitField<39, 3, IR::Pred> pred;
        BitField<42, 1, u64> neg_pred;
        BitField<43, 2, u64> mode;
        BitField<47, 1, u64> cc;
        BitField<48, 1, u64> is_signed;
    } const imnmx{insn};

    if (imnmx.cc != 0) {
        throw NotImplementedException("IMNMX CC");
    }

    if (imnmx.mode != 0) {
        throw NotImplementedException("IMNMX.MODE");
    }

    const IR::U1 pred{v.ir.GetPred(imnmx.pred)};
    const IR::U32 op_a{v.X(imnmx.src_reg)};
    IR::U32 min;
    IR::U32 max;

    if (imnmx.is_signed != 0) {
        min = IR::U32{v.ir.SMin(op_a, op_b)};
        max = IR::U32{v.ir.SMax(op_a, op_b)};
    } else {
        min = IR::U32{v.ir.UMin(op_a, op_b)};
        max = IR::U32{v.ir.UMax(op_a, op_b)};
    }
    if (imnmx.neg_pred != 0) {
        std::swap(min, max);
    }

    const IR::U32 result{v.ir.Select(pred, min, max)};
    v.X(imnmx.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::IMNMX_reg(u64 insn) {
    IMNMX(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::IMNMX_cbuf(u64 insn) {
    IMNMX(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::IMNMX_imm(u64 insn) {
    IMNMX(*this, insn, GetImm20(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void POPC(TranslatorVisitor& v, u64 insn, const IR::U32& src) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<40, 1, u64> tilde;
    } const popc{insn};

    const IR::U32 operand = popc.tilde == 0 ? src : v.ir.BitwiseNot(src);
    const IR::U32 result = v.ir.BitCount(operand);
    v.X(popc.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::POPC_reg(u64 insn) {
    POPC(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::POPC_cbuf(u64 insn) {
    POPC(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::POPC_imm(u64 insn) {
    POPC(*this, insn, GetImm20(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void ISCADD(TranslatorVisitor& v, u64 insn, IR::U32 op_b, bool cc, bool neg_a, bool neg_b,
            u64 scale_imm) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> op_a;
    } const iscadd{insn};

    const bool po{neg_a && neg_b};
    IR::U32 op_a{v.X(iscadd.op_a)};
    if (po) {
        // When PO is present, add one
        op_b = v.ir.IAdd(op_b, v.ir.Imm32(1));
    } else {
        // When PO is not present, the bits are interpreted as negation
        if (neg_a) {
            op_a = v.ir.INeg(op_a);
        }
        if (neg_b) {
            op_b = v.ir.INeg(op_b);
        }
    }
    // With the operands already processed, scale A
    const IR::U32 scale{v.ir.Imm32(static_cast<u32>(scale_imm))};
    const IR::U32 scaled_a{v.ir.ShiftLeftLogical(op_a, scale)};

    const IR::U32 result{v.ir.IAdd(scaled_a, op_b)};
    v.X(iscadd.dest_reg, result);

    if (cc) {
        v.SetZFlag(v.ir.GetZeroFromOp(result));
        v.SetSFlag(v.ir.GetSignFromOp(result));
        const IR::U1 carry{v.ir.GetCarryFromOp(result)};
        const IR::U1 overflow{v.ir.GetOverflowFromOp(result)};
        v.SetCFlag(po ? v.ir.LogicalOr(carry, v.ir.GetCarryFromOp(op_b)) : carry);
        v.SetOFlag(po ? v.ir.LogicalOr(overflow, v.ir.GetOverflowFromOp(op_b)) : overflow);
    }
}

void ISCADD(TranslatorVisitor& v, u64 insn, IR::U32 op_b) {
    union {
        u64 raw;
        BitField<47, 1, u64> cc;
        BitField<48, 1, u64> neg_b;
        BitField<49, 1, u64> neg_a;
        BitField<39, 5, u64> scale;
    } const iscadd{insn};

    ISCADD(v, insn, op_b, iscadd.cc != 0, iscadd.neg_a != 0, iscadd.neg_b != 0, iscadd.scale);
}

} // Anonymous namespace

void TranslatorVisitor::ISCADD_reg(u64 insn) {
    ISCADD(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::ISCADD_cbuf(u64 insn) {
    ISCADD(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::ISCADD_imm(u64 insn) {
    ISCADD(*this, insn, GetImm20(insn));
}

void TranslatorVisitor::ISCADD32I(u64 insn) {
    union {
        u64 raw;
        BitField<52, 1, u64> cc;
        BitField<53, 5, u64> scale;
    } const iscadd{insn};

    return ISCADD(*this, insn, GetImm32(insn), iscadd.cc != 0, false, false, iscadd.scale);
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
IR::U1 IsetpCompare(IR::IREmitter& ir, const IR::U32& operand_1, const IR::U32& operand_2,
                    CompareOp compare_op, bool is_signed, bool x) {
    return x ? ExtendedIntegerCompare(ir, operand_1, operand_2, compare_op, is_signed)
             : IntegerCompare(ir, operand_1, operand_2, compare_op, is_signed);
}

void ISETP(TranslatorVisitor& v, u64 insn, const IR::U32& op_b) {
    union {
        u64 raw;
        BitField<0, 3, IR::Pred> dest_pred_b;
        BitField<3, 3, IR::Pred> dest_pred_a;
        BitField<8, 8, IR::Reg> src_reg_a;
        BitField<39, 3, IR::Pred> bop_pred;
        BitField<42, 1, u64> neg_bop_pred;
        BitField<43, 1, u64> x;
        BitField<45, 2, BooleanOp> bop;
        BitField<48, 1, u64> is_signed;
        BitField<49, 3, CompareOp> compare_op;
    } const isetp{insn};

    const bool is_signed{isetp.is_signed != 0};
    const bool x{isetp.x != 0};
    const BooleanOp bop{isetp.bop};
    const CompareOp compare_op{isetp.compare_op};
    const IR::U32 op_a{v.X(isetp.src_reg_a)};
    const IR::U1 comparison{IsetpCompare(v.ir, op_a, op_b, compare_op, is_signed, x)};
    const IR::U1 bop_pred{v.ir.GetPred(isetp.bop_pred, isetp.neg_bop_pred != 0)};
    const IR::U1 result_a{PredicateCombine(v.ir, comparison, bop_pred, bop)};
    const IR::U1 result_b{PredicateCombine(v.ir, v.ir.LogicalNot(comparison), bop_pred, bop)};
    v.ir.SetPred(isetp.dest_pred_a, result_a);
    v.ir.SetPred(isetp.dest_pred_b, result_b);
}
} // Anonymous namespace

void TranslatorVisitor::ISETP_reg(u64 insn) {
    ISETP(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::ISETP_cbuf(u64 insn) {
    ISETP(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::ISETP_imm(u64 insn) {
    ISETP(*this, insn, GetImm20(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void SHL(TranslatorVisitor& v, u64 insn, const IR::U32& unsafe_shift) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_reg_a;
        BitField<39, 1, u64> w;
        BitField<43, 1, u64> x;
        BitField<47, 1, u64> cc;
    } const shl{insn};

    if (shl.x != 0) {
        throw NotImplementedException("SHL.X");
    }
    if (shl.cc != 0) {
        throw NotImplementedException("SHL.CC");
    }
    const IR::U32 base{v.X(shl.src_reg_a)};
    IR::U32 result;
    if (shl.w != 0) {
        // When .W is set, the shift value is wrapped
        // To emulate this we just have to wrap it ourselves.
        const IR::U32 shift{v.ir.BitwiseAnd(unsafe_shift, v.ir.Imm32(31))};
        result = v.ir.ShiftLeftLogical(base, shift);
    } else {
        // When .W is not set, the shift value is clamped between 0 and 32.
        // To emulate this we have to have in mind the special shift of 32, that evaluates as 0.
        // We can safely evaluate an out of bounds shift according to the SPIR-V specification:
        //
        // https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpShiftLeftLogical
        // "Shift is treated as unsigned. The resulting value is undefined if Shift is greater than
        //  or equal to the bit width of the components of Base."
        //
        // And on the GLASM specification it is also safe to evaluate out of bounds:
        //
        // https://www.khronos.org/registry/OpenGL/extensions/NV/NV_gpu_program4.txt
        // "The results of a shift operation ("<<") are undefined if the value of the second operand
        //  is negative, or greater than or equal to the number of bits in the first operand."
        //
        // Emphasis on undefined results in contrast to undefined behavior.
        //
        const IR::U1 is_safe{v.ir.ILessThan(unsafe_shift, v.ir.Imm32(32), false)};
        const IR::U32 unsafe_result{v.ir.ShiftLeftLogical(base, unsafe_shift)};
        result = IR::U32{v.ir.Select(is_safe, unsafe_result, v.ir.Imm32(0))};
    }
    v.X(shl.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::SHL_reg(u64 insn) {
    SHL(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::SHL_cbuf(u64 insn) {
    SHL(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::SHL_imm(u64 insn) {
    SHL(*this, insn, GetImm20(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void SHR(TranslatorVisitor& v, u64 insn, const IR::U32& shift) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_reg_a;
        BitField<39, 1, u64> is_wrapped;
        BitField<40, 1, u64> brev;
        BitField<43, 1, u64> xmode;
        BitField<47, 1, u64> cc;
        BitField<48, 1, u64> is_signed;
    } const shr{insn};

    if (shr.xmode != 0) {
        throw NotImplementedException("SHR.XMODE");
    }
    if (shr.cc != 0) {
        throw NotImplementedException("SHR.CC");
    }

    IR::U32 base{v.X(shr.src_reg_a)};
    if (shr.brev == 1) {
        base = v.ir.BitReverse(base);
    }
    IR::U32 result;
    const IR::U32 safe_shift = shr.is_wrapped == 0 ? shift : v.ir.BitwiseAnd(shift, v.ir.Imm32(31));
    if (shr.is_signed == 1) {
        result = IR::U32{v.ir.ShiftRightArithmetic(base, safe_shift)};
    } else {
        result = IR::U32{v.ir.ShiftRightLogical(base, safe_shift)};
    }

    if (shr.is_wrapped == 0) {
        const IR::U32 zero{v.ir.Imm32(0)};
        const IR::U32 safe_bits{v.ir.Imm32(32)};

        const IR::U1 is_negative{v.ir.ILessThan(result, zero, true)};
        const IR::U1 is_safe{v.ir.ILessThan(shift, safe_bits, false)};
        const IR::U32 clamped_value{v.ir.Select(is_negative, v.ir.Imm32(-1), zero)};
        result = IR::U32{v.ir.Select(is_safe, result, clamped_value)};
    }
    v.X(shr.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::SHR_reg(u64 insn) {
    SHR(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::SHR_cbuf(u64 insn) {
    SHR(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::SHR_imm(u64 insn) {
    SHR(*this, insn, GetImm20(insn));
}
} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class SelectMode : u64 {
    Default,
    CLO,
    CHI,
    CSFU,
    CBCC,
};

enum class Half : u64 {
    H0, // Least-significant bits (15:0)
    H1, // Most-significant bits (31:16)
};

IR::U32 ExtractHalf(TranslatorVisitor& v, const IR::U32& src, Half half, bool is_signed) {
    const IR::U32 offset{v.ir.Imm32(half == Half::H1 ? 16 : 0)};
    return v.ir.BitFieldExtract(src, offset, v.ir.Imm32(16), is_signed);
}

void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c,
          SelectMode select_mode, Half half_b, bool psl, bool mrg, bool x) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_reg_a;
        BitField<47, 1, u64> cc;
        BitField<48, 1, u64> is_a_signed;
        BitField<49, 1, u64> is_b_signed;
        BitField<53, 1, Half> half_a;
    } const xmad{insn};

    if (x) {
        throw NotImplementedException("XMAD X");
    }
    const IR::U32 op_a{ExtractHalf(v, v.X(xmad.src_reg_a), xmad.half_a, xmad.is_a_signed != 0)};
    const IR::U32 op_b{ExtractHalf(v, src_b, half_b, xmad.is_b_signed != 0)};

    IR::U32 product{v.ir.IMul(op_a, op_b)};
    if (psl) {
        // .PSL shifts the product 16 bits
        product = v.ir.ShiftLeftLogical(product, v.ir.Imm32(16));
    }
    const IR::U32 op_c{[&]() -> IR::U32 {
        switch (select_mode) {
        case SelectMode::Default:
            return src_c;
        case SelectMode::CLO:
            return ExtractHalf(v, src_c, Half::H0, false);
        case SelectMode::CHI:
            return ExtractHalf(v, src_c, Half::H1, false);
        case SelectMode::CBCC:
            return v.ir.IAdd(v.ir.ShiftLeftLogical(src_b, v.ir.Imm32(16)), src_c);
        case SelectMode::CSFU:
            throw NotImplementedException("XMAD CSFU");
        }
        throw NotImplementedException("Invalid XMAD select mode {}", select_mode);
    }()};
    IR::U32 result{v.ir.IAdd(product, op_c)};
    if (mrg) {
        // .MRG inserts src_b [15:0] into result's [31:16].
        const IR::U32 lsb_b{ExtractHalf(v, src_b, Half::H0, false)};
        result = v.ir.BitFieldInsert(result, lsb_b, v.ir.Imm32(16), v.ir.Imm32(16));
    }
    if (xmad.cc) {
        throw NotImplementedException("XMAD CC");
    }
    // Store result
    v.X(xmad.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::XMAD_reg(u64 insn) {
    union {
        u64 raw;
        BitField<35, 1, Half> half_b;
        BitField<36, 1, u64> psl;
        BitField<37, 1, u64> mrg;
        BitField<38, 1, u64> x;
        BitField<50, 3, SelectMode> select_mode;
    } const xmad{insn};

    XMAD(*this, insn, GetReg20(insn), GetReg39(insn), xmad.select_mode, xmad.half_b, xmad.psl != 0,
         xmad.mrg != 0, xmad.x != 0);
}

void TranslatorVisitor::XMAD_rc(u64 insn) {
    union {
        u64 raw;
        BitField<50, 2, SelectMode> select_mode;
        BitField<52, 1, Half> half_b;
        BitField<54, 1, u64> x;
    } const xmad{insn};

    XMAD(*this, insn, GetReg39(insn), GetCbuf(insn), xmad.select_mode, xmad.half_b, false, false,
         xmad.x != 0);
}

void TranslatorVisitor::XMAD_cr(u64 insn) {
    union {
        u64 raw;
        BitField<50, 2, SelectMode> select_mode;
        BitField<52, 1, Half> half_b;
        BitField<54, 1, u64> x;
        BitField<55, 1, u64> psl;
        BitField<56, 1, u64> mrg;
    } const xmad{insn};

    XMAD(*this, insn, GetCbuf(insn), GetReg39(insn), xmad.select_mode, xmad.half_b, xmad.psl != 0,
         xmad.mrg != 0, xmad.x != 0);
}

void TranslatorVisitor::XMAD_imm(u64 insn) {
    union {
        u64 raw;
        BitField<20, 16, u64> src_b;
        BitField<36, 1, u64> psl;
        BitField<37, 1, u64> mrg;
        BitField<38, 1, u64> x;
        BitField<50, 3, SelectMode> select_mode;
    } const xmad{insn};

    XMAD(*this, insn, ir.Imm32(static_cast<u32>(xmad.src_b)), GetReg39(insn), xmad.select_mode,
         Half::H0, xmad.psl != 0, xmad.mrg != 0, xmad.x != 0);
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class IntegerWidth : u64 {
    Byte,
    Short,
    Word,
};

[[nodiscard]] IR::U32 WidthSize(IR::IREmitter& ir, IntegerWidth width) {
    switch (width) {
    case IntegerWidth::Byte:
        return ir.Imm32(8);
    case IntegerWidth::Short:
        return ir.Imm32(16);
    case IntegerWidth::Word:
        return ir.Imm32(32);
    default:
        throw NotImplementedException("Invalid width {}", width);
    }
}

[[nodiscard]] IR::U32 ConvertInteger(IR::IREmitter& ir, const IR::U32& src,
                                     IntegerWidth dst_width) {
    const IR::U32 zero{ir.Imm32(0)};
    const IR::U32 count{WidthSize(ir, dst_width)};
    return ir.BitFieldExtract(src, zero, count, false);
}

[[nodiscard]] IR::U32 SaturateInteger(IR::IREmitter& ir, const IR::U32& src, IntegerWidth dst_width,
                                      bool dst_signed, bool src_signed) {
    IR::U32 min{};
    IR::U32 max{};
    const IR::U32 zero{ir.Imm32(0)};
    switch (dst_width) {
    case IntegerWidth::Byte:
        min = dst_signed && src_signed ? ir.Imm32(0xffffff80) : zero;
        max = dst_signed ? ir.Imm32(0x7f) : ir.Imm32(0xff);
        break;
    case IntegerWidth::Short:
        min = dst_signed && src_signed ? ir.Imm32(0xffff8000) : zero;
        max = dst_signed ? ir.Imm32(0x7fff) : ir.Imm32(0xffff);
        break;
    case IntegerWidth::Word:
        min = dst_signed && src_signed ? ir.Imm32(0x80000000) : zero;
        max = dst_signed ? ir.Imm32(0x7fffffff) : ir.Imm32(0xffffffff);
        break;
    default:
        throw NotImplementedException("Invalid width {}", dst_width);
    }
    const IR::U32 value{!dst_signed && src_signed ? ir.SMax(zero, src) : src};
    return dst_signed && src_signed ? ir.SClamp(value, min, max) : ir.UClamp(value, min, max);
}

void I2I(TranslatorVisitor& v, u64 insn, const IR::U32& src_a) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 2, IntegerWidth> dst_fmt;
        BitField<12, 1, u64> dst_fmt_sign;
        BitField<10, 2, IntegerWidth> src_fmt;
        BitField<13, 1, u64> src_fmt_sign;
        BitField<41, 3, u64> selector;
        BitField<45, 1, u64> neg;
        BitField<47, 1, u64> cc;
        BitField<49, 1, u64> abs;
        BitField<50, 1, u64> sat;
    } const i2i{insn};

    if (i2i.src_fmt == IntegerWidth::Short && (i2i.selector == 1 || i2i.selector == 3)) {
        throw NotImplementedException("16-bit source format incompatible with selector {}",
                                      i2i.selector);
    }
    if (i2i.src_fmt == IntegerWidth::Word && i2i.selector != 0) {
        throw NotImplementedException("32-bit source format incompatible with selector {}",
                                      i2i.selector);
    }

    const s32 selector{static_cast<s32>(i2i.selector)};
    const IR::U32 offset{v.ir.Imm32(selector * 8)};
    const IR::U32 count{WidthSize(v.ir, i2i.src_fmt)};
    const bool src_signed{i2i.src_fmt_sign != 0};
    const bool dst_signed{i2i.dst_fmt_sign != 0};
    const bool sat{i2i.sat != 0};

    IR::U32 src_values{v.ir.BitFieldExtract(src_a, offset, count, src_signed)};
    if (i2i.abs != 0) {
        src_values = v.ir.IAbs(src_values);
    }
    if (i2i.neg != 0) {
        src_values = v.ir.INeg(src_values);
    }
    const IR::U32 result{
        sat ? SaturateInteger(v.ir, src_values, i2i.dst_fmt, dst_signed, src_signed)
            : ConvertInteger(v.ir, src_values, i2i.dst_fmt)};

    v.X(i2i.dest_reg, result);
    if (i2i.cc != 0) {
        v.SetZFlag(v.ir.GetZeroFromOp(result));
        v.SetSFlag(v.ir.GetSignFromOp(result));
        v.ResetCFlag();
        v.ResetOFlag();
    }
}
} // Anonymous namespace

void TranslatorVisitor::I2I_reg(u64 insn) {
    I2I(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::I2I_cbuf(u64 insn) {
    I2I(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::I2I_imm(u64 insn) {
    I2I(*this, insn, GetImm20(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class Mode : u64 {
    Default,
    Patch,
    Prim,
    Attr,
};

enum class Shift : u64 {
    Default,
    U16,
    B32,
};

} // Anonymous namespace

void TranslatorVisitor::ISBERD(u64 insn) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> src_reg;
        BitField<31, 1, u64> skew;
        BitField<32, 1, u64> o;
        BitField<33, 2, Mode> mode;
        BitField<47, 2, Shift> shift;
    } const isberd{insn};

    if (isberd.skew != 0) {
        throw NotImplementedException("SKEW");
    }
    if (isberd.o != 0) {
        throw NotImplementedException("O");
    }
    if (isberd.mode != Mode::Default) {
        throw NotImplementedException("Mode {}", isberd.mode.Value());
    }
    if (isberd.shift != Shift::Default) {
        throw NotImplementedException("Shift {}", isberd.shift.Value());
    }
    LOG_WARNING(Shader, "(STUBBED) called");
    X(isberd.dest_reg, X(isberd.src_reg));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/load_constant.h"

namespace Shader::Maxwell {
using namespace LDC;
namespace {
std::pair<IR::U32, IR::U32> Slot(IR::IREmitter& ir, Mode mode, const IR::U32& imm_index,
                                 const IR::U32& reg, const IR::U32& imm_offset) {
    switch (mode) {
    case Mode::Default:
        return {imm_index, ir.IAdd(reg, imm_offset)};
    case Mode::IS: {
        // Segmented addressing mode
        // Ra+imm_offset points into a flat mapping of const buffer
        // address space
        const IR::U32 address{ir.IAdd(reg, imm_offset)};
        const IR::U32 index{ir.BitFieldExtract(address, ir.Imm32(16), ir.Imm32(16))};
        const IR::U32 offset{ir.BitFieldExtract(address, ir.Imm32(0), ir.Imm32(16))};

        return {ir.IAdd(index, imm_index), offset};
    }
    default:
        break;
    }
    throw NotImplementedException("Mode {}", mode);
}
} // Anonymous namespace

void TranslatorVisitor::LDC(u64 insn) {
    const Encoding ldc{insn};
    const IR::U32 imm_index{ir.Imm32(static_cast<u32>(ldc.index))};
    const IR::U32 reg{X(ldc.src_reg)};
    const IR::U32 imm{ir.Imm32(static_cast<s32>(ldc.offset))};
    const auto [index, offset]{Slot(ir, ldc.mode, imm_index, reg, imm)};
    switch (ldc.size) {
    case Size::U8:
        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 8, false)});
        break;
    case Size::S8:
        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 8, true)});
        break;
    case Size::U16:
        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 16, false)});
        break;
    case Size::S16:
        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 16, true)});
        break;
    case Size::B32:
        X(ldc.dest_reg, IR::U32{ir.GetCbuf(index, offset, 32, false)});
        break;
    case Size::B64: {
        if (!IR::IsAligned(ldc.dest_reg, 2)) {
            throw NotImplementedException("Unaligned destination register");
        }
        const IR::Value vector{ir.GetCbuf(index, offset, 64, false)};
        for (int i = 0; i < 2; ++i) {
            X(ldc.dest_reg + i, IR::U32{ir.CompositeExtract(vector, static_cast<size_t>(i))});
        }
        break;
    }
    default:
        throw NotImplementedException("Invalid size {}", ldc.size.Value());
    }
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/ir/reg.h"

namespace Shader::Maxwell::LDC {

enum class Mode : u64 {
    Default,
    IL,
    IS,
    ISL,
};

enum class Size : u64 {
    U8,
    S8,
    U16,
    S16,
    B32,
    B64,
};

union Encoding {
    u64 raw;
    BitField<0, 8, IR::Reg> dest_reg;
    BitField<8, 8, IR::Reg> src_reg;
    BitField<20, 16, s64> offset;
    BitField<36, 5, u64> index;
    BitField<44, 2, Mode> mode;
    BitField<48, 3, Size> size;
};

} // namespace Shader::Maxwell::LDC


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
void LEA_hi(TranslatorVisitor& v, u64 insn, const IR::U32& base, IR::U32 offset_hi, u64 scale,
            bool neg, bool x) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> offset_lo_reg;
        BitField<47, 1, u64> cc;
        BitField<48, 3, IR::Pred> pred;
    } const lea{insn};

    if (x) {
        throw NotImplementedException("LEA.HI X");
    }
    if (lea.pred != IR::Pred::PT) {
        throw NotImplementedException("LEA.HI Pred");
    }
    if (lea.cc != 0) {
        throw NotImplementedException("LEA.HI CC");
    }

    const IR::U32 offset_lo{v.X(lea.offset_lo_reg)};
    const IR::U64 packed_offset{v.ir.PackUint2x32(v.ir.CompositeConstruct(offset_lo, offset_hi))};
    const IR::U64 offset{neg ? IR::U64{v.ir.INeg(packed_offset)} : packed_offset};

    const s32 hi_scale{32 - static_cast<s32>(scale)};
    const IR::U64 scaled_offset{v.ir.ShiftRightLogical(offset, v.ir.Imm32(hi_scale))};
    const IR::U32 scaled_offset_w0{v.ir.CompositeExtract(v.ir.UnpackUint2x32(scaled_offset), 0)};

    IR::U32 result{v.ir.IAdd(base, scaled_offset_w0)};
    v.X(lea.dest_reg, result);
}

void LEA_lo(TranslatorVisitor& v, u64 insn, const IR::U32& base) {
    union {
        u64 insn;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> offset_lo_reg;
        BitField<39, 5, u64> scale;
        BitField<45, 1, u64> neg;
        BitField<46, 1, u64> x;
        BitField<47, 1, u64> cc;
        BitField<48, 3, IR::Pred> pred;
    } const lea{insn};
    if (lea.x != 0) {
        throw NotImplementedException("LEA.LO X");
    }
    if (lea.pred != IR::Pred::PT) {
        throw NotImplementedException("LEA.LO Pred");
    }
    if (lea.cc != 0) {
        throw NotImplementedException("LEA.LO CC");
    }

    const IR::U32 offset_lo{v.X(lea.offset_lo_reg)};
    const s32 scale{static_cast<s32>(lea.scale)};
    const IR::U32 offset{lea.neg != 0 ? IR::U32{v.ir.INeg(offset_lo)} : offset_lo};
    const IR::U32 scaled_offset{v.ir.ShiftLeftLogical(offset, v.ir.Imm32(scale))};

    IR::U32 result{v.ir.IAdd(base, scaled_offset)};
    v.X(lea.dest_reg, result);
}
} // Anonymous namespace

void TranslatorVisitor::LEA_hi_reg(u64 insn) {
    union {
        u64 insn;
        BitField<28, 5, u64> scale;
        BitField<37, 1, u64> neg;
        BitField<38, 1, u64> x;
    } const lea{insn};

    LEA_hi(*this, insn, GetReg20(insn), GetReg39(insn), lea.scale, lea.neg != 0, lea.x != 0);
}

void TranslatorVisitor::LEA_hi_cbuf(u64 insn) {
    union {
        u64 insn;
        BitField<51, 5, u64> scale;
        BitField<56, 1, u64> neg;
        BitField<57, 1, u64> x;
    } const lea{insn};

    LEA_hi(*this, insn, GetCbuf(insn), GetReg39(insn), lea.scale, lea.neg != 0, lea.x != 0);
}

void TranslatorVisitor::LEA_lo_reg(u64 insn) {
    LEA_lo(*this, insn, GetReg20(insn));
}

void TranslatorVisitor::LEA_lo_cbuf(u64 insn) {
    LEA_lo(*this, insn, GetCbuf(insn));
}

void TranslatorVisitor::LEA_lo_imm(u64 insn) {
    LEA_lo(*this, insn, GetImm20(insn));
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class Size : u64 {
    B32,
    B64,
    B96,
    B128,
};

enum class InterpolationMode : u64 {
    Pass,
    Multiply,
    Constant,
    Sc,
};

enum class SampleMode : u64 {
    Default,
    Centroid,
    Offset,
};

u32 NumElements(Size size) {
    switch (size) {
    case Size::B32:
        return 1;
    case Size::B64:
        return 2;
    case Size::B96:
        return 3;
    case Size::B128:
        return 4;
    }
    throw InvalidArgument("Invalid size {}", size);
}

template <typename F>
void HandleIndexed(TranslatorVisitor& v, IR::Reg index_reg, u32 num_elements, F&& f) {
    const IR::U32 index_value{v.X(index_reg)};
    for (u32 element = 0; element < num_elements; ++element) {
        const IR::U32 final_offset{
            element == 0 ? index_value : IR::U32{v.ir.IAdd(index_value, v.ir.Imm32(element * 4U))}};
        f(element, final_offset);
    }
}

} // Anonymous namespace

void TranslatorVisitor::ALD(u64 insn) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> index_reg;
        BitField<20, 10, u64> absolute_offset;
        BitField<20, 11, s64> relative_offset;
        BitField<39, 8, IR::Reg> vertex_reg;
        BitField<32, 1, u64> o;
        BitField<31, 1, u64> patch;
        BitField<47, 2, Size> size;
    } const ald{insn};

    const u64 offset{ald.absolute_offset.Value()};
    if (offset % 4 != 0) {
        throw NotImplementedException("Unaligned absolute offset {}", offset);
    }
    const IR::U32 vertex{X(ald.vertex_reg)};
    const u32 num_elements{NumElements(ald.size)};
    if (ald.index_reg == IR::Reg::RZ) {
        for (u32 element = 0; element < num_elements; ++element) {
            if (ald.patch != 0) {
                const IR::Patch patch{offset / 4 + element};
                F(ald.dest_reg + static_cast<int>(element), ir.GetPatch(patch));
            } else {
                const IR::Attribute attr{offset / 4 + element};
                F(ald.dest_reg + static_cast<int>(element), ir.GetAttribute(attr, vertex));
            }
        }
        return;
    }
    if (ald.patch != 0) {
        throw NotImplementedException("Indirect patch read");
    }
    HandleIndexed(*this, ald.index_reg, num_elements, [&](u32 element, IR::U32 final_offset) {
        F(ald.dest_reg + static_cast<int>(element), ir.GetAttributeIndexed(final_offset, vertex));
    });
}

void TranslatorVisitor::AST(u64 insn) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> src_reg;
        BitField<8, 8, IR::Reg> index_reg;
        BitField<20, 10, u64> absolute_offset;
        BitField<20, 11, s64> relative_offset;
        BitField<31, 1, u64> patch;
        BitField<39, 8, IR::Reg> vertex_reg;
        BitField<47, 2, Size> size;
    } const ast{insn};

    if (ast.index_reg != IR::Reg::RZ) {
        throw NotImplementedException("Indexed store");
    }
    const u64 offset{ast.absolute_offset.Value()};
    if (offset % 4 != 0) {
        throw NotImplementedException("Unaligned absolute offset {}", offset);
    }
    const IR::U32 vertex{X(ast.vertex_reg)};
    const u32 num_elements{NumElements(ast.size)};
    if (ast.index_reg == IR::Reg::RZ) {
        for (u32 element = 0; element < num_elements; ++element) {
            if (ast.patch != 0) {
                const IR::Patch patch{offset / 4 + element};
                ir.SetPatch(patch, F(ast.src_reg + static_cast<int>(element)));
            } else {
                const IR::Attribute attr{offset / 4 + element};
                ir.SetAttribute(attr, F(ast.src_reg + static_cast<int>(element)), vertex);
            }
        }
        return;
    }
    if (ast.patch != 0) {
        throw NotImplementedException("Indexed tessellation patch store");
    }
    HandleIndexed(*this, ast.index_reg, num_elements, [&](u32 element, IR::U32 final_offset) {
        ir.SetAttributeIndexed(final_offset, F(ast.src_reg + static_cast<int>(element)), vertex);
    });
}

void TranslatorVisitor::IPA(u64 insn) {
    // IPA is the instruction used to read varyings from a fragment shader.
    // gl_FragCoord is mapped to the gl_Position attribute.
    // It yields unknown results when used outside of the fragment shader stage.
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<8, 8, IR::Reg> index_reg;
        BitField<20, 8, IR::Reg> multiplier;
        BitField<30, 8, IR::Attribute> attribute;
        BitField<38, 1, u64> idx;
        BitField<51, 1, u64> sat;
        BitField<52, 2, SampleMode> sample_mode;
        BitField<54, 2, InterpolationMode> interpolation_mode;
    } const ipa{insn};

    // Indexed IPAs are used for indexed varyings.
    // For example:
    //
    // in vec4 colors[4];
    // uniform int idx;
    // void main() {
    //     gl_FragColor = colors[idx];
    // }
    const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ};
    const IR::Attribute attribute{ipa.attribute};
    IR::F32 value{is_indexed ? ir.GetAttributeIndexed(X(ipa.index_reg))
                             : ir.GetAttribute(attribute)};
    if (IR::IsGeneric(attribute)) {
        const ProgramHeader& sph{env.SPH()};
        const u32 attr_index{IR::GenericAttributeIndex(attribute)};
        const u32 element{static_cast<u32>(attribute) % 4};
        const std::array input_map{sph.ps.GenericInputMap(attr_index)};
        const bool is_perspective{input_map[element] == Shader::PixelImap::Perspective};
        if (is_perspective) {
            const IR::F32 position_w{ir.GetAttribute(IR::Attribute::PositionW)};
            value = ir.FPMul(value, position_w);
        }
    }
    if (ipa.interpolation_mode == InterpolationMode::Multiply) {
        value = ir.FPMul(value, F(ipa.multiplier));
    }

    // Saturated IPAs are generally generated out of clamped varyings.
    // For example: clamp(some_varying, 0.0, 1.0)
    const bool is_saturated{ipa.sat != 0};
    if (is_saturated) {
        if (attribute == IR::Attribute::FrontFace) {
            throw NotImplementedException("IPA.SAT on FrontFace");
        }
        value = ir.FPSaturate(value);
    }

    F(ipa.dest_reg, value);
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class Size : u64 {
    U8,
    S8,
    U16,
    S16,
    B32,
    B64,
    B128,
};

IR::U32 Offset(TranslatorVisitor& v, u64 insn) {
    union {
        u64 raw;
        BitField<8, 8, IR::Reg> offset_reg;
        BitField<20, 24, u64> absolute_offset;
        BitField<20, 24, s64> relative_offset;
    } const encoding{insn};

    if (encoding.offset_reg == IR::Reg::RZ) {
        return v.ir.Imm32(static_cast<u32>(encoding.absolute_offset));
    } else {
        const s32 relative{static_cast<s32>(encoding.relative_offset.Value())};
        return v.ir.IAdd(v.X(encoding.offset_reg), v.ir.Imm32(relative));
    }
}

std::pair<IR::U32, IR::U32> WordOffset(TranslatorVisitor& v, u64 insn) {
    const IR::U32 offset{Offset(v, insn)};
    if (offset.IsImmediate()) {
        return {v.ir.Imm32(offset.U32() / 4), offset};
    } else {
        return {v.ir.ShiftRightArithmetic(offset, v.ir.Imm32(2)), offset};
    }
}

std::pair<int, bool> GetSize(u64 insn) {
    union {
        u64 raw;
        BitField<48, 3, Size> size;
    } const encoding{insn};

    switch (encoding.size) {
    case Size::U8:
        return {8, false};
    case Size::S8:
        return {8, true};
    case Size::U16:
        return {16, false};
    case Size::S16:
        return {16, true};
    case Size::B32:
        return {32, false};
    case Size::B64:
        return {64, false};
    case Size::B128:
        return {128, false};
    default:
        throw NotImplementedException("Invalid size {}", encoding.size.Value());
    }
}

IR::Reg Reg(u64 insn) {
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> reg;
    } const encoding{insn};

    return encoding.reg;
}

IR::U32 ByteOffset(IR::IREmitter& ir, const IR::U32& offset) {
    return ir.BitwiseAnd(ir.ShiftLeftLogical(offset, ir.Imm32(3)), ir.Imm32(24));
}

IR::U32 ShortOffset(IR::IREmitter& ir, const IR::U32& offset) {
    return ir.BitwiseAnd(ir.ShiftLeftLogical(offset, ir.Imm32(3)), ir.Imm32(16));
}

IR::U32 LoadLocal(TranslatorVisitor& v, const IR::U32& word_offset, const IR::U32& offset) {
    const IR::U32 local_memory_size{v.ir.Imm32(v.env.LocalMemorySize())};
    const IR::U1 in_bounds{v.ir.ILessThan(offset, local_memory_size, false)};
    return IR::U32{v.ir.Select(in_bounds, v.ir.LoadLocal(word_offset), v.ir.Imm32(0))};
}
} // Anonymous namespace

void TranslatorVisitor::LDL(u64 insn) {
    const auto [word_offset, offset]{WordOffset(*this, insn)};
    const IR::U32 word{LoadLocal(*this, word_offset, offset)};
    const IR::Reg dest{Reg(insn)};
    const auto [bit_size, is_signed]{GetSize(insn)};
    switch (bit_size) {
    case 8: {
        const IR::U32 bit{ByteOffset(ir, offset)};
        X(dest, ir.BitFieldExtract(word, bit, ir.Imm32(8), is_signed));
        break;
    }
    case 16: {
        const IR::U32 bit{ShortOffset(ir, offset)};
        X(dest, ir.BitFieldExtract(word, bit, ir.Imm32(16), is_signed));
        break;
    }
    case 32:
    case 64:
    case 128:
        if (!IR::IsAligned(dest, static_cast<size_t>(bit_size / 32))) {
            throw NotImplementedException("Unaligned destination register {}", dest);
        }
        X(dest, word);
        for (int i = 1; i < bit_size / 32; ++i) {
            const IR::U32 sub_word_offset{ir.IAdd(word_offset, ir.Imm32(i))};
            const IR::U32 sub_offset{ir.IAdd(offset, ir.Imm32(i * 4))};
            X(dest + i, LoadLocal(*this, sub_word_offset, sub_offset));
        }
        break;
    }
}

void TranslatorVisitor::LDS(u64 insn) {
    const IR::U32 offset{Offset(*this, insn)};
    const IR::Reg dest{Reg(insn)};
    const auto [bit_size, is_signed]{GetSize(insn)};
    const IR::Value value{ir.LoadShared(bit_size, is_signed, offset)};
    switch (bit_size) {
    case 8:
    case 16:
    case 32:
        X(dest, IR::U32{value});
        break;
    case 64:
    case 128:
        if (!IR::IsAligned(dest, static_cast<size_t>(bit_size / 32))) {
            throw NotImplementedException("Unaligned destination register {}", dest);
        }
        for (int element = 0; element < bit_size / 32; ++element) {
            X(dest + element, IR::U32{ir.CompositeExtract(value, static_cast<size_t>(element))});
        }
        break;
    }
}

void TranslatorVisitor::STL(u64 insn) {
    const auto [word_offset, offset]{WordOffset(*this, insn)};
    if (offset.IsImmediate()) {
        // TODO: Support storing out of bounds at runtime
        if (offset.U32() >= env.LocalMemorySize()) {
            LOG_WARNING(Shader, "Storing local memory at 0x{:x} with a size of 0x{:x}, dropping",
                        offset.U32(), env.LocalMemorySize());
            return;
        }
    }
    const IR::Reg reg{Reg(insn)};
    const IR::U32 src{X(reg)};
    const int bit_size{GetSize(insn).first};
    switch (bit_size) {
    case 8: {
        const IR::U32 bit{ByteOffset(ir, offset)};
        const IR::U32 value{ir.BitFieldInsert(ir.LoadLocal(word_offset), src, bit, ir.Imm32(8))};
        ir.WriteLocal(word_offset, value);
        break;
    }
    case 16: {
        const IR::U32 bit{ShortOffset(ir, offset)};
        const IR::U32 value{ir.BitFieldInsert(ir.LoadLocal(word_offset), src, bit, ir.Imm32(16))};
        ir.WriteLocal(word_offset, value);
        break;
    }
    case 32:
    case 64:
    case 128:
        if (!IR::IsAligned(reg, static_cast<size_t>(bit_size / 32))) {
            throw NotImplementedException("Unaligned source register");
        }
        ir.WriteLocal(word_offset, src);
        for (int i = 1; i < bit_size / 32; ++i) {
            ir.WriteLocal(ir.IAdd(word_offset, ir.Imm32(i)), X(reg + i));
        }
        break;
    }
}

void TranslatorVisitor::STS(u64 insn) {
    const IR::U32 offset{Offset(*this, insn)};
    const IR::Reg reg{Reg(insn)};
    const int bit_size{GetSize(insn).first};
    switch (bit_size) {
    case 8:
    case 16:
    case 32:
        ir.WriteShared(bit_size, offset, X(reg));
        break;
    case 64:
        if (!IR::IsAligned(reg, 2)) {
            throw NotImplementedException("Unaligned source register {}", reg);
        }
        ir.WriteShared(64, offset, ir.CompositeConstruct(X(reg), X(reg + 1)));
        break;
    case 128: {
        if (!IR::IsAligned(reg, 2)) {
            throw NotImplementedException("Unaligned source register {}", reg);
        }
        const IR::Value vector{ir.CompositeConstruct(X(reg), X(reg + 1), X(reg + 2), X(reg + 3))};
        ir.WriteShared(128, offset, vector);
        break;
    }
    }
}

} // namespace Shader::Maxwell


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"

namespace Shader::Maxwell {
namespace {
enum class LoadSize : u64 {
    U8,  // Zero-extend
    S8,  // Sign-extend
    U16, // Zero-extend
    S16, // Sign-extend
    B32,
    B64,
    B128,
    U128, // ???
};

enum class StoreSize : u64 {
    U8,  // Zero-extend
    S8,  // Sign-extend
    U16, // Zero-extend
    S16, // Sign-extend
    B32,
    B64,
    B128,
};

// See Table 27 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
enum class LoadCache : u64 {
    CA, // Cache at all levels, likely to be accessed again
    CG, // Cache at global level (cache in L2 and below, not L1)
    CI, // ???
    CV, // Don't cache and fetch again (consider cached system memory lines stale, fetch again)
};

// See Table 28 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
enum class StoreCache : u64 {
    WB, // Cache write-back all coherent levels
    CG, // Cache at global level
    CS, // Cache streaming, likely to be accessed once
    WT, // Cache write-through (to system memory)
};

IR::U64 Address(TranslatorVisitor& v, u64 insn) {
    union {
        u64 raw;
        BitField<8, 8, IR::Reg> addr_reg;
        BitField<20, 24, s64> addr_offset;
        BitField<20, 24, u64> rz_addr_offset;
        BitField<45, 1, u64> e;
    } const mem{insn};

    const IR::U64 address{[&]() -> IR::U64 {
        if (mem.e == 0) {
            // LDG/STG without .E uses a 32-bit pointer, zero-extend it
            return v.ir.UConvert(64, v.X(mem.addr_reg));
        }
        if (!IR::IsAligned(mem.addr_reg, 2)) {
            throw NotImplementedException("Unaligned address register");
        }
        // Pack two registers to build the 64-bit address
        return v.ir.PackUint2x32(v.ir.CompositeConstruct(v.X(mem.addr_reg), v.X(mem.addr_reg + 1)));
    }()};
    const u64 addr_offset{[&]() -> u64 {
        if (mem.addr_reg == IR::Reg::RZ) {
            // When RZ is used, the address is an absolute address
            return static_cast<u64>(mem.rz_addr_offset.Value());
        } else {
            return static_cast<u64>(mem.addr_offset.Value());
        }
    }()};
    // Apply the offset
    return v.ir.IAdd(address, v.ir.Imm64(addr_offset));
}
} // Anonymous namespace

void TranslatorVisitor::LDG(u64 insn) {
    // LDG loads global memory into registers
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> dest_reg;
        BitField<46, 2, LoadCache> cache;
        BitField<48, 3, LoadSize> size;
    } const ldg{insn};

    // Pointer to load data from
    const IR::U64 address{Address(*this, insn)};
    const IR::Reg dest_reg{ldg.dest_reg};
    switch (ldg.size) {
    case LoadSize::U8:
        X(dest_reg, ir.LoadGlobalU8(address));
        break;
    case LoadSize::S8:
        X(dest_reg, ir.LoadGlobalS8(address));
        break;
    case LoadSize::U16:
        X(dest_reg, ir.LoadGlobalU16(address));
        break;
    case LoadSize::S16:
        X(dest_reg, ir.LoadGlobalS16(address));
        break;
    case LoadSize::B32:
        X(dest_reg, ir.LoadGlobal32(address));
        break;
    case LoadSize::B64: {
        if (!IR::IsAligned(dest_reg, 2)) {
            throw NotImplementedException("Unaligned data registers");
        }
        const IR::Value vector{ir.LoadGlobal64(address)};
        for (int i = 0; i < 2; ++i) {
            X(dest_reg + i, IR::U32{ir.CompositeExtract(vector, static_cast<size_t>(i))});
        }
        break;
    }
    case LoadSize::B128:
    case LoadSize::U128: {
        if (!IR::IsAligned(dest_reg, 4)) {
            throw NotImplementedException("Unaligned data registers");
        }
        const IR::Value vector{ir.LoadGlobal128(address)};
        for (int i = 0; i < 4; ++i) {
            X(dest_reg + i, IR::U32{ir.CompositeExtract(vector, static_cast<size_t>(i))});
        }
        break;
    }
    default:
        throw NotImplementedException("Invalid LDG size {}", ldg.size.Value());
    }
}

void TranslatorVisitor::STG(u64 insn) {
    // STG stores registers into global memory.
    union {
        u64 raw;
        BitField<0, 8, IR::Reg> data_reg;
        BitField<46, 2, StoreCache> cache;
        BitField<48, 3, StoreSize> size;
    } const stg{insn};

    // Pointer to store data into
    const IR::U64 address{Address(*this, insn)};
    const IR::Reg data_reg{stg.data_reg};
    switch (stg.size) {
    case StoreSize::U8:
        ir.WriteGlobalU8(address, X(data_reg));
        break;
    case StoreSize::S8:
        ir.WriteGlobalS8(address, X(data_reg));
        break;
    case StoreSize::U16:
        ir.WriteGlobalU16(address, X(data_reg));
        break;
    case StoreSize::S16:
        ir.WriteGlobalS16(address, X(data_reg));
        break;
    case StoreSize::B32:
        ir.WriteGlobal32(address, X(data_reg));
        break;
    case StoreSize::B64: {
        if (!IR::IsAligned(data_reg, 2)) {
            throw NotImplementedException("Unaligned data registers");
        }
        const IR::Value vector{ir.CompositeConstruct(X(data_reg), X(data_reg + 1))};
        ir.WriteGlobal64(address, vector);
        break;
    }
    case StoreSize::B128:
        if (!IR::IsAligned(data_reg, 4)) {
            throw NotImplementedException("Unaligned data registers");
        }
        const IR::Value vector{
            ir.CompositeConstruct(X(data_reg), X(data_reg + 1), X(data_reg + 2), X(data_reg + 3))};
        ir.WriteGlobal128(address, vector);
        break;
    }
}

} // namespace Shader::Maxwell