Revert "shader: preserve raw VCC bits in S_MOV_B64 (#418)"

This reverts commit 6758d67942.

An EXEC pair loses its mask provenance and falls into the raw high-word path. The saved all-ones high word then keeps waterfall branches true and wedges GPU work.
This commit is contained in:
nmzik
2026-09-01 07:32:18 +04:00
parent b8a459e83d
commit e591a66b67
13 changed files with 185 additions and 444 deletions
@@ -12,7 +12,6 @@ void Translator::EmitCompareResult(const Decoder::Instruction& inst, IR::U1 valu
if (cmpx) {
const auto mask = BallotMask(masked);
ir.SetExec(masked);
ir.SetExecMaskTag(IR::U1(IR::Value(true)));
ir.SetExecLo(mask[0]);
ir.SetExecHi(mask[1]);
return;
@@ -24,28 +24,18 @@ Decoder::Operand ConditionOperand(Decoder::OperandKind kind) {
void Translator::S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode operation,
bool negate_exec, bool negate_source, bool write_64) {
if (write_64) {
const auto exec_operand = ConditionOperand(Decoder::OperandKind::ExecLo);
const auto old = ReadScalarU64(exec_operand);
const auto bit_operation = operation == IR::ValueOpcode::LogicalAnd
? IR::ValueOpcode::BitwiseAnd32
: IR::ValueOpcode::BitwiseOr32;
const auto result = BinaryScalarU64(old, ReadScalarU64(inst.src0), operation, bit_operation,
negate_exec, negate_source, false);
WriteScalarU64(inst.dst, old);
WriteScalarU64(exec_operand, result);
ir.SetScc(ScalarU64NonZero(result));
return;
}
const auto old = ir.GetExec();
const auto src = ReadMask(inst.src0);
const auto lhs = negate_exec ? ir.LogicalNot(old) : old;
const auto rhs = negate_source ? ir.LogicalNot(src) : src;
const auto result = IR::U1(ir.Emit(operation, {lhs, rhs}));
WriteMask(inst.dst, old);
if (write_64) {
WriteMask64(inst.dst, old);
} else {
WriteMask(inst.dst, old);
}
const auto mask = BallotMask(result);
ir.SetExec(result);
ir.SetExecMaskTag(IR::U1(IR::Value(true)));
ir.SetExecLo(mask[0]);
ir.SetExecHi(mask[1]);
ir.SetScc(result);
@@ -201,21 +191,30 @@ void Translator::S_CSELECT_B32(const Decoder::Instruction& inst) {
}
void Translator::S_CSELECT_B64(const Decoder::Instruction& inst) {
const auto condition = ir.GetScc();
const auto lhs = ReadScalarU64(inst.src0);
const auto rhs = ReadScalarU64(inst.src1);
WriteScalarU64(inst.dst, SelectScalarU64(condition, lhs, rhs));
const auto condition = ir.GetScc();
const auto lhs = ReadU32Pair(inst.src0);
const auto rhs = ReadU32Pair(inst.src1);
const auto selected_mask = IR::U1(
ir.Emit(IR::ValueOpcode::SelectU1, {condition, ReadMask(inst.src0), ReadMask(inst.src1)}));
const auto selected_mask_valid =
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1,
{condition, ReadMaskValid(inst.src0), ReadMaskValid(inst.src1)}));
if (IsExecOrVcc(inst.dst)) {
WriteMask64(inst.dst, selected_mask);
return;
}
WriteU32Pair(inst.dst,
{ir.Select(condition, lhs[0], rhs[0]), ir.Select(condition, lhs[1], rhs[1])});
if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
ir.SetThreadBitScalarReg(dst, selected_mask);
ir.SetScalarMaskTag(dst, selected_mask_valid);
}
}
void Translator::MOV_B32(const Decoder::Instruction& inst, bool apply_float_modifiers) {
if (inst.src0.kind == Decoder::OperandKind::Sgpr &&
inst.dst.kind == Decoder::OperandKind::Sgpr && inst.src0.reg == inst.dst.reg) {
return;
}
if (IsExecOrVcc(inst.src0) && IsExecOrVcc(inst.dst)) {
if (inst.src0.kind != inst.dst.kind) {
WriteRawU32(inst.dst, ReadRawU32(inst.src0));
}
WriteMask(inst.dst, ReadMask(inst.src0));
} else if (apply_float_modifiers && (inst.src0.negate || inst.src0.absolute)) {
WriteOperand(DestinationOperand(inst), ReadOperand(inst.src0, IR::Type::F32));
} else {
@@ -224,17 +223,50 @@ void Translator::MOV_B32(const Decoder::Instruction& inst, bool apply_float_modi
}
void Translator::S_MOV_B64(const Decoder::Instruction& inst) {
WriteScalarU64(inst.dst, ReadScalarU64(inst.src0));
if (IsExecOrVcc(inst.dst) || IsExecOrVcc(inst.src0)) {
WriteMask64(inst.dst, ReadMask(inst.src0));
return;
}
const bool scalar_copy =
inst.dst.kind == Decoder::OperandKind::Sgpr && inst.src0.kind == Decoder::OperandKind::Sgpr;
IR::U1 source_mask;
IR::U1 source_mask_valid;
if (scalar_copy) {
source_mask = ir.GetThreadBitScalarReg(static_cast<IR::ScalarReg>(inst.src0.reg));
source_mask_valid = ir.GetScalarMaskTag(static_cast<IR::ScalarReg>(inst.src0.reg));
}
WriteU32Pair(inst.dst, ReadU32Pair(inst.src0));
if (scalar_copy) {
ir.SetThreadBitScalarReg(static_cast<IR::ScalarReg>(inst.dst.reg), source_mask);
ir.SetScalarMaskTag(static_cast<IR::ScalarReg>(inst.dst.reg), source_mask_valid);
}
}
void Translator::S_WQM_B64(const Decoder::Instruction& inst) {
const auto source = ReadScalarU64(inst.src0);
const auto raw = ExtractU64(
IR::U64(ir.Emit(IR::ValueOpcode::WqmU64, {ir.ConstructU64(source.raw[0], source.raw[1])})));
const auto invocation = IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {source.invocation}));
const auto result = MakeScalarU64Result(raw, invocation, source.mask_valid);
WriteScalarU64(inst.dst, result);
ir.SetScc(ScalarU64NonZero(result));
if (!IsExecOrVcc(inst.dst) && !IsExecOrVcc(inst.src0)) {
const auto mask_valid = ReadMaskValid(inst.src0);
const auto invocation_result =
IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src0)}));
const auto result =
IR::U64(ir.Emit(IR::ValueOpcode::WqmU64, {ReadOperand(inst.src0, IR::Type::U64)}));
WriteOperand(DestinationOperand(inst), result);
if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
ir.SetThreadBitScalarReg(dst, invocation_result);
ir.SetScalarMaskTag(dst, mask_valid);
const auto raw_nonzero =
IR::U1(ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})}));
ir.SetScc(IR::U1(
ir.Emit(IR::ValueOpcode::SelectU1, {mask_valid, invocation_result, raw_nonzero})));
} else {
ir.SetScc(
IR::U1(ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})})));
}
return;
}
const auto result = IR::U1(ir.Emit(IR::ValueOpcode::WqmMask, {ReadMask(inst.src0)}));
WriteMask64(inst.dst, result);
ir.SetScc(result);
}
void Translator::V_MOVRELS_B32(const Decoder::Instruction& inst) {
@@ -77,15 +77,68 @@ bool Translator::PackedInteger16MinMax(const Decoder::Instruction& inst, IR::Val
return true;
}
IR::U1 Translator::U64MaskBinary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,
bool negate_rhs, bool negate_result) {
const auto lhs = ReadMask(inst.src0);
auto rhs = ReadMask(inst.src1);
if (negate_rhs) {
rhs = ir.LogicalNot(rhs);
}
auto result = IR::U1(ir.Emit(opcode, {lhs, rhs}));
return negate_result ? ir.LogicalNot(result) : result;
}
bool Translator::S_U64_MASK(const Decoder::Instruction& inst, IR::ValueOpcode logical_opcode,
IR::ValueOpcode bit_opcode, bool negate_rhs, bool negate_result,
bool unary) {
const auto lhs = ReadScalarU64(inst.src0);
const auto result = unary ? NotScalarU64(lhs)
: BinaryScalarU64(lhs, ReadScalarU64(inst.src1), logical_opcode,
bit_opcode, false, negate_rhs, negate_result);
WriteScalarU64(inst.dst, result);
ir.SetScc(ScalarU64NonZero(result));
const auto invocation_result =
unary ? ir.LogicalNot(ReadMask(inst.src0))
: U64MaskBinary(inst, logical_opcode, negate_rhs, negate_result);
const auto is_exec_or_vcc = [](const Decoder::Operand& operand) {
switch (operand.kind) {
case Decoder::OperandKind::ExecLo:
case Decoder::OperandKind::ExecHi:
case Decoder::OperandKind::VccLo:
case Decoder::OperandKind::VccHi: return true;
default: return false;
}
};
if (is_exec_or_vcc(inst.dst) || is_exec_or_vcc(inst.src0) ||
(inst.src_count > 1u && is_exec_or_vcc(inst.src1))) {
WriteMask64(inst.dst, invocation_result);
ir.SetScc(invocation_result);
return true;
}
const auto lhs = ReadU32Pair(inst.src0);
auto mask_valid = ReadMaskValid(inst.src0);
if (inst.src_count > 1u) {
mask_valid = ir.LogicalAnd(mask_valid, ReadMaskValid(inst.src1));
}
std::array<IR::U32, 2> result;
if (unary) {
result = {ir.BitwiseNot(lhs[0]), ir.BitwiseNot(lhs[1])};
} else {
const auto rhs = ReadU32Pair(inst.src1);
for (uint32_t component = 0; component < 2u; component++) {
auto value = ir.Emit(
bit_opcode, {lhs[component], negate_rhs ? IR::Value(ir.BitwiseNot(rhs[component]))
: IR::Value(rhs[component])});
result[component] = negate_result ? ir.BitwiseNot(IR::U32(value)) : IR::U32(value);
}
}
WriteU32Pair(inst.dst, result);
if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
ir.SetThreadBitScalarReg(dst, invocation_result);
ir.SetScalarMaskTag(dst, mask_valid);
const auto raw_nonzero =
ir.INotEqual(ir.BitwiseOr(result[0], result[1]), IR::U32(IR::Value(0u)));
ir.SetScc(IR::U1(
ir.Emit(IR::ValueOpcode::SelectU1, {mask_valid, invocation_result, raw_nonzero})));
} else {
ir.SetScc(ir.INotEqual(ir.BitwiseOr(result[0], result[1]), IR::U32(IR::Value(0u))));
}
return true;
}
@@ -55,14 +55,11 @@ uint32_t ResourceIndexFromOperand(const Decoder::Operand& operand) {
}
}
Decoder::Operand RawScalarLoadBase(const Decoder::Operand& operand) {
if (operand.kind != Decoder::OperandKind::M0) {
return operand;
uint32_t RawScalarLoadBase(const Decoder::Operand& operand) {
if (operand.kind == Decoder::OperandKind::Sgpr) {
return operand.reg;
}
auto result = operand;
// The compressed SBASE value 62 decodes as code 124, but means NULL for S_LOAD.
result.kind = Decoder::OperandKind::Null;
return result;
return operand.kind == Decoder::OperandKind::VccLo ? 106u : 0u;
}
ResourceKind FlatSegmentResourceKind(uint32_t segment) {
@@ -322,9 +319,8 @@ Translator::AddressOperands Translator::ReadAddressOperands(const Decoder::Instr
return {GetAddressResource(low, high), low, high};
}
IR::Value Translator::GetScalarAddressResource(const Decoder::Operand& base) {
const auto raw = ReadU32Pair(base);
return GetAddressResource(raw[0], raw[1]);
IR::Value Translator::GetScalarAddressResource(uint32_t base) {
return GetAddressResource(ReadScalarCode(base), ReadScalarCode(base + 1u));
}
IR::Value Translator::GetImageResource(const IR::MemoryInfo& memory) {
@@ -151,8 +151,11 @@ IR::U32 Translator::ReadScalarCode(uint32_t code) {
case 106u: return ir.GetVccLo();
case 107u: return ir.GetVccHi();
case 124u: return ir.GetM0();
case 126u: return ir.GetExecLo();
case 127u: return ir.GetExecHi();
case 126u:
case 127u: {
const auto mask = BallotMask(ir.GetExec());
return mask[code - 126u];
}
default: return IR::U32(IR::Value(0u));
}
}
@@ -312,23 +315,19 @@ void Translator::WriteRawU32(const Decoder::Operand& operand, IR::U32 value) {
case Decoder::OperandKind::VccLo:
ir.SetVccLo(IR::U32(value));
ir.SetVcc(ThreadBit(IR::U32(value)));
ir.SetVccMaskValidTag(IR::U1(IR::Value(false)));
break;
case Decoder::OperandKind::VccHi:
ir.SetVccHi(IR::U32(value));
ir.SetVcc(ThreadBit(ir.GetVccLo()));
ir.SetVccMaskValidTag(IR::U1(IR::Value(false)));
break;
case Decoder::OperandKind::M0: ir.SetM0(IR::U32(value)); break;
case Decoder::OperandKind::ExecLo:
ir.SetExecLo(IR::U32(value));
ir.SetExec(ThreadBit(IR::U32(value)));
ir.SetExecMaskTag(IR::U1(IR::Value(false)));
break;
case Decoder::OperandKind::ExecHi:
ir.SetExecHi(IR::U32(value));
ir.SetExec(ThreadBit(ir.GetExecLo()));
ir.SetExecMaskTag(IR::U1(IR::Value(false)));
break;
case Decoder::OperandKind::Scc:
ir.SetScc(ir.INotEqual(value, IR::U32(IR::Value(0u))));
@@ -373,7 +372,6 @@ void Translator::WriteOperand(const Decoder::Operand& operand, IR::Value value)
case Decoder::OperandKind::ExecHi: {
const auto mask = BallotMask(IR::U1(value));
ir.SetExec(IR::U1(value));
ir.SetExecMaskTag(IR::U1(IR::Value(true)));
ir.SetExecLo(mask[0]);
ir.SetExecHi(mask[1]);
return;
@@ -382,7 +380,6 @@ void Translator::WriteOperand(const Decoder::Operand& operand, IR::Value value)
case Decoder::OperandKind::VccHi: {
const auto mask = BallotMask(IR::U1(value));
ir.SetVcc(IR::U1(value));
ir.SetVccMaskValidTag(IR::U1(IR::Value(true)));
ir.SetVccLo(mask[0]);
ir.SetVccHi(mask[1]);
return;
@@ -583,13 +580,11 @@ void Translator::WriteU32Pair(const Decoder::Operand& operand,
switch (operand.kind) {
case Decoder::OperandKind::ExecLo:
ir.SetExec(thread_bit);
ir.SetExecMaskTag(IR::U1(IR::Value(false)));
ir.SetExecLo(value[0]);
ir.SetExecHi(value[1]);
return;
case Decoder::OperandKind::VccLo:
ir.SetVcc(thread_bit);
ir.SetVccMaskValidTag(IR::U1(IR::Value(false)));
ir.SetVccLo(value[0]);
ir.SetVccHi(value[1]);
return;
@@ -600,87 +595,6 @@ void Translator::WriteU32Pair(const Decoder::Operand& operand,
WriteRawU32(OffsetOperand(operand, 1), value[1]);
}
Translator::ScalarU64 Translator::ReadScalarU64(const Decoder::Operand& operand) {
return {ReadU32Pair(operand), ReadMask(operand), ReadMaskValid(operand)};
}
Translator::ScalarU64 Translator::MakeScalarU64Mask(IR::U1 value) {
return {BallotMask(value), value, IR::U1(IR::Value(true))};
}
Translator::ScalarU64 Translator::MakeScalarU64Result(const std::array<IR::U32, 2>& raw,
IR::U1 invocation, IR::U1 mask_valid) {
return {raw,
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1, {mask_valid, invocation, ThreadBit(raw[0])})),
mask_valid};
}
Translator::ScalarU64 Translator::SelectScalarU64(IR::U1 condition, const ScalarU64& lhs,
const ScalarU64& rhs) {
return {
{ir.Select(condition, lhs.raw[0], rhs.raw[0]),
ir.Select(condition, lhs.raw[1], rhs.raw[1])},
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1, {condition, lhs.invocation, rhs.invocation})),
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1, {condition, lhs.mask_valid, rhs.mask_valid}))};
}
Translator::ScalarU64 Translator::NotScalarU64(const ScalarU64& value) {
return MakeScalarU64Result({ir.BitwiseNot(value.raw[0]), ir.BitwiseNot(value.raw[1])},
ir.LogicalNot(value.invocation), value.mask_valid);
}
Translator::ScalarU64 Translator::BinaryScalarU64(const ScalarU64& lhs, const ScalarU64& rhs,
IR::ValueOpcode logical_opcode,
IR::ValueOpcode bit_opcode, bool negate_lhs,
bool negate_rhs, bool negate_result) {
auto lhs_mask = negate_lhs ? ir.LogicalNot(lhs.invocation) : lhs.invocation;
auto rhs_mask = negate_rhs ? ir.LogicalNot(rhs.invocation) : rhs.invocation;
auto mask = IR::U1(ir.Emit(logical_opcode, {lhs_mask, rhs_mask}));
if (negate_result) {
mask = ir.LogicalNot(mask);
}
std::array<IR::U32, 2> raw;
for (uint32_t component = 0; component < raw.size(); component++) {
auto lhs_raw = negate_lhs ? ir.BitwiseNot(lhs.raw[component]) : lhs.raw[component];
auto rhs_raw = negate_rhs ? ir.BitwiseNot(rhs.raw[component]) : rhs.raw[component];
raw[component] = IR::U32(ir.Emit(bit_opcode, {lhs_raw, rhs_raw}));
if (negate_result) {
raw[component] = ir.BitwiseNot(raw[component]);
}
}
return MakeScalarU64Result(raw, mask, ir.LogicalAnd(lhs.mask_valid, rhs.mask_valid));
}
void Translator::WriteScalarU64(const Decoder::Operand& operand, const ScalarU64& value) {
WriteU32Pair(operand, value.raw);
switch (operand.kind) {
case Decoder::OperandKind::ExecLo:
case Decoder::OperandKind::ExecHi:
ir.SetExec(value.invocation);
ir.SetExecMaskTag(value.mask_valid);
break;
case Decoder::OperandKind::VccLo:
case Decoder::OperandKind::VccHi:
ir.SetVcc(value.invocation);
ir.SetVccMaskValidTag(value.mask_valid);
break;
case Decoder::OperandKind::Sgpr: {
const auto reg = static_cast<IR::ScalarReg>(operand.reg);
ir.SetThreadBitScalarReg(reg, value.invocation);
ir.SetScalarMaskTag(reg, value.mask_valid);
break;
}
default: break;
}
}
IR::U1 Translator::ScalarU64NonZero(const ScalarU64& value) {
const auto raw_nonzero =
ir.INotEqual(ir.BitwiseOr(value.raw[0], value.raw[1]), IR::U32(IR::Value(0u)));
return IR::U1(
ir.Emit(IR::ValueOpcode::SelectU1, {value.mask_valid, value.invocation, raw_nonzero}));
}
IR::U1 Translator::ThreadBit(IR::U32 low) {
return ir.INotEqual(low, IR::U32(IR::Value(0u)));
}
@@ -736,9 +650,9 @@ IR::U1 Translator::ReadMaskValid(const Decoder::Operand& operand) {
case Decoder::OperandKind::Sgpr:
return ir.GetScalarMaskTag(static_cast<IR::ScalarReg>(operand.reg));
case Decoder::OperandKind::ExecLo:
case Decoder::OperandKind::ExecHi: return ir.GetExecMaskTag();
case Decoder::OperandKind::ExecHi:
case Decoder::OperandKind::VccLo:
case Decoder::OperandKind::VccHi: return ir.GetVccMaskValidTag();
case Decoder::OperandKind::VccHi:
case Decoder::OperandKind::VccZ:
case Decoder::OperandKind::ExecZ:
case Decoder::OperandKind::Scc: return IR::U1(IR::Value(true));
@@ -771,7 +685,6 @@ void Translator::WriteMask(const Decoder::Operand& operand, IR::U1 value) {
case Decoder::OperandKind::ExecHi: {
const auto mask = BallotMask(value);
ir.SetExec(value);
ir.SetExecMaskTag(IR::U1(IR::Value(true)));
ir.SetExecLo(mask[0]);
ir.SetExecHi(mask[1]);
return;
@@ -780,7 +693,6 @@ void Translator::WriteMask(const Decoder::Operand& operand, IR::U1 value) {
case Decoder::OperandKind::VccHi: {
const auto mask = BallotMask(value);
ir.SetVcc(value);
ir.SetVccMaskValidTag(IR::U1(IR::Value(true)));
ir.SetVccLo(mask[0]);
ir.SetVccHi(mask[1]);
return;
@@ -794,7 +706,25 @@ void Translator::WriteMask(const Decoder::Operand& operand, IR::U1 value) {
}
void Translator::WriteMask64(const Decoder::Operand& operand, IR::U1 value) {
WriteScalarU64(operand, MakeScalarU64Mask(value));
if (operand.kind != Decoder::OperandKind::Sgpr) {
WriteMask(operand, value);
return;
}
const auto reg = static_cast<IR::ScalarReg>(operand.reg);
const auto mask = BallotMask(value);
ir.SetThreadBitScalarReg(reg, value);
ir.SetScalarMaskTag(reg, IR::U1(IR::Value(true)));
if (IR::RegIndex(reg) > 0u) {
ir.SetScalarMaskTag(static_cast<IR::ScalarReg>(IR::RegIndex(reg) - 1u),
IR::U1(IR::Value(false)));
}
ir.SetScalarReg(reg, mask[0]);
if (IR::RegIndex(reg) + 1u < IR::NumScalarRegs) {
const auto high = static_cast<IR::ScalarReg>(IR::RegIndex(reg) + 1u);
ir.SetScalarReg(high, mask[1]);
ir.SetThreadBitScalarReg(high, IR::U1(IR::Value(false)));
ir.SetScalarMaskTag(high, IR::U1(IR::Value(false)));
}
}
void Translator::WriteCompareResult(const Decoder::Operand& operand, IR::U1 value) {
@@ -1095,7 +1025,6 @@ IR::Program TranslateProgram(const Decoder::Program& decoded, const CFG::Graph&
entry_ir.SetScalarMaskTag(reg, IR::U1(IR::Value(false)));
}
entry_ir.SetExec(IR::U1(IR::Value(true)));
entry_ir.SetExecMaskTag(IR::U1(IR::Value(true)));
entry_ir.SetExecLo(IR::U32(IR::Value(1u)));
entry_ir.SetExecHi(IR::U32(IR::Value(0u)));
if (options.stage == ShaderType::Compute) {
@@ -19,14 +19,6 @@ public:
void AddBranchCondition(const CFG::BasicBlock& source, IR::BlockInfo& info);
private:
struct ScalarU64 {
std::array<IR::U32, 2> raw;
// Raw words and Kyty's per-invocation mask model remain independent.
// mask_valid selects invocation for logical consumers and SCC.
IR::U1 invocation;
IR::U1 mask_valid;
};
Decoder::Operand SourceAt(const Decoder::Instruction& inst, uint32_t index);
Decoder::Operand DestinationOperand(const Decoder::Instruction& inst);
Decoder::Operand OffsetOperand(const Decoder::Operand& operand, uint32_t offset);
@@ -56,25 +48,14 @@ private:
IR::U32 ReadU16AsU32(const Decoder::Operand& operand, bool sign_extend);
IR::U32 ReadF16LaneBits(const Decoder::Operand& operand, bool high_lane);
std::array<IR::U32, 2> ExtractU64(IR::U64 value);
void WriteU32Pair(const Decoder::Operand& operand, const std::array<IR::U32, 2>& value);
ScalarU64 ReadScalarU64(const Decoder::Operand& operand);
ScalarU64 MakeScalarU64Mask(IR::U1 value);
ScalarU64 MakeScalarU64Result(const std::array<IR::U32, 2>& raw, IR::U1 invocation,
IR::U1 mask_valid);
ScalarU64 SelectScalarU64(IR::U1 condition, const ScalarU64& lhs, const ScalarU64& rhs);
ScalarU64 NotScalarU64(const ScalarU64& value);
ScalarU64 BinaryScalarU64(const ScalarU64& lhs, const ScalarU64& rhs,
IR::ValueOpcode logical_opcode, IR::ValueOpcode bit_opcode,
bool negate_lhs, bool negate_rhs, bool negate_result);
void WriteScalarU64(const Decoder::Operand& operand, const ScalarU64& value);
IR::U1 ScalarU64NonZero(const ScalarU64& value);
IR::U1 ReadCondition(const Decoder::Operand& operand);
IR::U32 ConditionBit(const Decoder::Operand& operand);
IR::U1 ReadMask(const Decoder::Operand& operand);
IR::U1 ReadMaskValid(const Decoder::Operand& operand);
void WriteMask(const Decoder::Operand& operand, IR::U1 value);
void WriteMask64(const Decoder::Operand& operand, IR::U1 value);
void WriteCompareResult(const Decoder::Operand& operand, IR::U1 value);
void WriteU32Pair(const Decoder::Operand& operand, const std::array<IR::U32, 2>& value);
IR::U1 ReadCondition(const Decoder::Operand& operand);
IR::U32 ConditionBit(const Decoder::Operand& operand);
IR::U1 ReadMask(const Decoder::Operand& operand);
IR::U1 ReadMaskValid(const Decoder::Operand& operand);
void WriteMask(const Decoder::Operand& operand, IR::U1 value);
void WriteMask64(const Decoder::Operand& operand, IR::U1 value);
void WriteCompareResult(const Decoder::Operand& operand, IR::U1 value);
IR::MemoryFlags AddMemoryInfo(const IR::MemoryInfo& memory, uint32_t pc);
IR::ExportFlags AddExportInfo(const Decoder::Instruction& inst);
@@ -92,7 +73,7 @@ private:
IR::U32 GetResourceDword(uint32_t index, uint32_t dword);
IR::Value GetBufferResource(const IR::MemoryInfo& memory);
IR::Value GetAddressResource(IR::Value low, IR::Value high);
IR::Value GetScalarAddressResource(const Decoder::Operand& base);
IR::Value GetScalarAddressResource(uint32_t base);
IR::Value GetImageResource(const IR::MemoryInfo& memory);
IR::Value GetSamplerResource(const IR::MemoryInfo& memory);
IR::Value MakeImageAddress(const Decoder::Instruction& inst, const Decoder::Operand& base);
@@ -194,6 +175,8 @@ private:
bool PackedInteger16MinMax(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool sign);
bool S_U64_MASK(const Decoder::Instruction& inst, IR::ValueOpcode logical_opcode,
IR::ValueOpcode bit_opcode, bool negate_rhs, bool negate_result, bool unary);
IR::U1 U64MaskBinary(const Decoder::Instruction& inst, IR::ValueOpcode opcode, bool negate_rhs,
bool negate_result);
bool SimpleInteger(const Decoder::Instruction& inst, IR::ValueOpcode opcode, IR::Type type,
bool reverse, bool mask_shift_count, bool update_scc);
bool ComposedIntegerBinary(const Decoder::Instruction& inst, IR::ValueOpcode opcode,