mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-06-10 01:18:18 +02:00
kraid: Add Src/Dst data types
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41841>
This commit is contained in:
parent
eaead919d5
commit
3de388f652
2 changed files with 352 additions and 0 deletions
351
src/panfrost/compiler/kraid/ir.rs
Normal file
351
src/panfrost/compiler/kraid/ir.rs
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
// Copyright © 2026 Collabora, Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pub use crate::data_type::DataType;
|
||||
pub use crate::ssa_value::{SSARef, SSAValue};
|
||||
pub use crate::swizzle::Swizzle;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub enum FAUPage {
|
||||
/// The user FAU table. This assumes a single, flat table, unlike the
|
||||
/// hardware which splits the user FAU into 4 pages. In Kraid, the page
|
||||
/// split for the user FAU is handled by the back-end as a per-generation
|
||||
/// constraint, not represented in the IR.
|
||||
User,
|
||||
|
||||
/// FAU special page 0
|
||||
Special0,
|
||||
|
||||
/// FAU special page 3
|
||||
Special1,
|
||||
|
||||
/// FAU special page 3
|
||||
Special3,
|
||||
|
||||
/// The small constant table
|
||||
SmallConst,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FAURef {
|
||||
pub page: FAUPage,
|
||||
|
||||
/// The FAU index, in units of 32-bit words. The hardware uses 64-bit
|
||||
/// words and has a word select bit in the source encoding. In this
|
||||
/// representation, the bottom bit is the word select and the upper 15 bits
|
||||
/// are the 64-bit FAU index. For 64-bit access, the bottom bit must be
|
||||
/// zero.
|
||||
pub idx: u16,
|
||||
|
||||
/// Load 64 bytes
|
||||
pub load64: bool,
|
||||
}
|
||||
|
||||
impl fmt::Display for FAURef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.page == FAUPage::SmallConst {
|
||||
debug_assert!(!self.load64);
|
||||
return write!(f, "k{}", self.idx);
|
||||
}
|
||||
|
||||
let idx = self.idx >> 1;
|
||||
let w = self.idx % 1;
|
||||
|
||||
match self.page {
|
||||
FAUPage::User => write!(f, "u{idx}")?,
|
||||
FAUPage::Special0 => write!(f, "s0:{idx}")?,
|
||||
FAUPage::Special1 => write!(f, "s1:{idx}")?,
|
||||
FAUPage::Special3 => write!(f, "s3:{idx}")?,
|
||||
FAUPage::SmallConst => panic!("Already handled"),
|
||||
}
|
||||
|
||||
if self.load64 {
|
||||
debug_assert_eq!(w, 0);
|
||||
} else {
|
||||
write!(f, ".w{w}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct describes the range of registers read or written by a RegRef.
|
||||
/// The range provided here acts as a mask on the destination but is purely
|
||||
/// informational for sources. In all cases, the instruction operates relative
|
||||
/// to the register itself. If a source needs to read from a value in the top
|
||||
/// half of a register, it is swizzled accordingly. For 16-bit destinations,
|
||||
/// the instruction itself continues to operate 32 bits wide and the register
|
||||
/// write is simply masked.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RegRange {
|
||||
Half0,
|
||||
Half1,
|
||||
Regs(u8),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct RegRef {
|
||||
pub idx: u8,
|
||||
pub range: RegRange,
|
||||
}
|
||||
|
||||
impl fmt::Display for RegRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self.range {
|
||||
RegRange::Half0 => write!(f, "r{}.h0", self.idx),
|
||||
RegRange::Half1 => write!(f, "r{}.h1", self.idx),
|
||||
RegRange::Regs(n) => {
|
||||
write!(f, "r{}", self.idx)?;
|
||||
if *n > 1 {
|
||||
write!(f, "..{}", self.idx + n)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RegRef {
|
||||
fn bytes(&self) -> u8 {
|
||||
match self.range {
|
||||
RegRange::Half0 | RegRange::Half1 => 2,
|
||||
RegRange::Regs(n) => n * 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SrcRef {
|
||||
/// A 32-bit immediate
|
||||
Imm32(u32),
|
||||
FAU(FAURef),
|
||||
SSA(SSARef),
|
||||
Reg(RegRef),
|
||||
}
|
||||
|
||||
impl fmt::Display for SrcRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
SrcRef::Imm32(u) => write!(f, "{u:#x}"),
|
||||
SrcRef::FAU(fau) => fau.fmt(f),
|
||||
SrcRef::SSA(ssa) => ssa.fmt(f),
|
||||
SrcRef::Reg(reg) => reg.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SrcRef {
|
||||
/// Returns the number of bytes read
|
||||
pub fn bytes_read(&self) -> u8 {
|
||||
match self {
|
||||
SrcRef::Imm32(_) => 4,
|
||||
SrcRef::FAU(fau) => {
|
||||
if fau.load64 {
|
||||
8
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
SrcRef::SSA(vec) => vec.bytes(),
|
||||
SrcRef::Reg(reg) => reg.bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_small_const(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
SrcRef::FAU(FAURef {
|
||||
page: FAUPage::SmallConst,
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for SrcRef {
|
||||
fn from(u: u32) -> SrcRef {
|
||||
SrcRef::Imm32(u)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FAURef> for SrcRef {
|
||||
fn from(fau: FAURef) -> SrcRef {
|
||||
SrcRef::FAU(fau)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<SSARef>> From<T> for SrcRef {
|
||||
fn from(ssa: T) -> SrcRef {
|
||||
SrcRef::SSA(ssa.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RegRef> for SrcRef {
|
||||
fn from(reg: RegRef) -> SrcRef {
|
||||
SrcRef::Reg(reg)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
|
||||
pub enum SrcMod {
|
||||
#[default]
|
||||
None = 0,
|
||||
FAbs = 1,
|
||||
FNeg = 2,
|
||||
FNegAbs = 3,
|
||||
BNot = 4,
|
||||
}
|
||||
|
||||
impl fmt::Display for SrcMod {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
SrcMod::None => Ok(()),
|
||||
SrcMod::FAbs => write!(f, ".fabs"),
|
||||
SrcMod::FNeg => write!(f, ".fneg"),
|
||||
SrcMod::FNegAbs => write!(f, ".fabs.fneg"),
|
||||
SrcMod::BNot => write!(f, ".bnot"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SrcMod {
|
||||
pub fn bnot(self) -> SrcMod {
|
||||
use SrcMod::*;
|
||||
match self {
|
||||
None => BNot,
|
||||
FAbs | FNeg | FNegAbs => {
|
||||
panic!("Cannot compose float and bitwise modifiers");
|
||||
}
|
||||
BNot => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fabs(self) -> SrcMod {
|
||||
use SrcMod::*;
|
||||
match self {
|
||||
None | FAbs | FNeg | FNegAbs => FAbs,
|
||||
BNot => panic!("Cannot compose float and bitwise modifiers"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fneg(self) -> SrcMod {
|
||||
use SrcMod::*;
|
||||
match self {
|
||||
None => FNeg,
|
||||
FAbs => FNegAbs,
|
||||
FNeg => None,
|
||||
FNegAbs => FAbs,
|
||||
BNot => panic!("Cannot compose float and bitwise modifiers"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify(self, other: SrcMod) -> SrcMod {
|
||||
use SrcMod::*;
|
||||
match other {
|
||||
None => self,
|
||||
FAbs => self.fabs(),
|
||||
FNeg => self.fneg(),
|
||||
FNegAbs => self.fabs().fneg(),
|
||||
BNot => self.bnot(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Src {
|
||||
pub src_ref: SrcRef,
|
||||
pub swizzle: Swizzle,
|
||||
pub src_mod: SrcMod,
|
||||
pub last_use: bool,
|
||||
}
|
||||
|
||||
impl fmt::Display for Src {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let lu = if self.last_use { "^" } else { "" };
|
||||
write!(f, "{}{lu}{}{}", self.src_ref, self.swizzle, self.src_mod)
|
||||
}
|
||||
}
|
||||
|
||||
impl Src {
|
||||
pub fn swizzle(mut self, swizzle: Swizzle) -> Src {
|
||||
self.swizzle = self.swizzle.swizzle(swizzle).unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn byte(self, byte: u8) -> Src {
|
||||
self.swizzle(Swizzle::replicate_byte(byte))
|
||||
}
|
||||
|
||||
pub fn half(self, half: u8) -> Src {
|
||||
self.swizzle(Swizzle::replicate_half(half))
|
||||
}
|
||||
|
||||
pub fn modify(mut self, src_mod: SrcMod) -> Src {
|
||||
self.src_mod = self.src_mod.modify(src_mod);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bnot(self) -> Src {
|
||||
self.modify(SrcMod::BNot)
|
||||
}
|
||||
|
||||
pub fn fabs(self) -> Src {
|
||||
self.modify(SrcMod::FAbs)
|
||||
}
|
||||
|
||||
pub fn fneg(self) -> Src {
|
||||
self.modify(SrcMod::FNeg)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<SrcRef>> From<T> for Src {
|
||||
fn from(src_ref: T) -> Src {
|
||||
Src {
|
||||
src_ref: src_ref.into(),
|
||||
swizzle: Default::default(),
|
||||
src_mod: Default::default(),
|
||||
last_use: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Dst {
|
||||
None,
|
||||
SSA(SSARef),
|
||||
Reg(RegRef),
|
||||
}
|
||||
|
||||
impl fmt::Display for Dst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Dst::None => write!(f, "null"),
|
||||
Dst::SSA(ssa) => ssa.fmt(f),
|
||||
Dst::Reg(reg) => reg.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dst {
|
||||
pub fn bytes_written(&self) -> u8 {
|
||||
match self {
|
||||
Dst::None => 0,
|
||||
Dst::SSA(vec) => vec.bytes(),
|
||||
Dst::Reg(reg) => reg.bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<SSARef>> From<T> for Dst {
|
||||
fn from(ssa: T) -> Dst {
|
||||
Dst::SSA(ssa.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RegRef> for Dst {
|
||||
fn from(reg: RegRef) -> Dst {
|
||||
Dst::Reg(reg)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
mod compile;
|
||||
mod data_type;
|
||||
mod ir;
|
||||
mod model;
|
||||
mod ssa_value;
|
||||
mod swizzle;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue