mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-07 06:30:11 +01:00
nak,compiler: Move AsSlice to common code
Reviewed-by: Christian Gmeiner <cgmeiner@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30443>
This commit is contained in:
parent
3ca448a549
commit
ab72be6c5e
8 changed files with 282 additions and 246 deletions
28
src/compiler/rust/as_slice.rs
Normal file
28
src/compiler/rust/as_slice.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright © 2024 Collabora, Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::ops::Index;
|
||||
|
||||
pub enum AttrList<T: 'static> {
|
||||
Array(&'static [T]),
|
||||
Uniform(T),
|
||||
}
|
||||
|
||||
impl<T: 'static> Index<usize> for AttrList<T> {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, idx: usize) -> &T {
|
||||
match self {
|
||||
AttrList::Array(arr) => &arr[idx],
|
||||
AttrList::Uniform(typ) => typ,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsSlice<T> {
|
||||
type Attr;
|
||||
|
||||
fn as_slice(&self) -> &[T];
|
||||
fn as_mut_slice(&mut self) -> &mut [T];
|
||||
fn attrs(&self) -> AttrList<Self::Attr>;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © 2024 Igalia S.L.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pub mod as_slice;
|
||||
pub mod bindings;
|
||||
pub mod bitset;
|
||||
pub mod cfg;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
_compiler_rs_sources = [
|
||||
'as_slice.rs',
|
||||
'bitset.rs',
|
||||
'cfg.rs',
|
||||
'nir.rs',
|
||||
|
|
@ -94,3 +95,21 @@ _libcompiler_rs = static_library(
|
|||
idep_compiler_rs = declare_dependency(
|
||||
link_with : _libcompiler_rs,
|
||||
)
|
||||
|
||||
dep_syn = dependency('syn',
|
||||
version : '>= 2.0.15',
|
||||
fallback : ['syn', 'dep_syn'],
|
||||
required : true,
|
||||
)
|
||||
|
||||
_libcompiler_proc_rs = static_library(
|
||||
'compiler_proc',
|
||||
'proc/lib.rs',
|
||||
gnu_symbol_visibility : 'hidden',
|
||||
dependencies : [dep_syn],
|
||||
rust_abi : 'rust',
|
||||
)
|
||||
|
||||
idep_compiler_proc_rs = declare_dependency(
|
||||
link_with : _libcompiler_proc_rs,
|
||||
)
|
||||
|
|
|
|||
220
src/compiler/rust/proc/as_slice.rs
Normal file
220
src/compiler/rust/proc/as_slice.rs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
// Copyright © 2023 Collabora, Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use syn::*;
|
||||
|
||||
fn expr_as_usize(expr: &syn::Expr) -> usize {
|
||||
let lit = match expr {
|
||||
syn::Expr::Lit(lit) => lit,
|
||||
_ => panic!("Expected a literal, found an expression"),
|
||||
};
|
||||
let lit_int = match &lit.lit {
|
||||
syn::Lit::Int(i) => i,
|
||||
_ => panic!("Expected a literal integer"),
|
||||
};
|
||||
assert!(lit.attrs.is_empty());
|
||||
lit_int
|
||||
.base10_parse()
|
||||
.expect("Failed to parse integer literal")
|
||||
}
|
||||
|
||||
fn count_type(ty: &Type, slice_type: &str) -> usize {
|
||||
match ty {
|
||||
syn::Type::Array(a) => {
|
||||
let elems = count_type(a.elem.as_ref(), slice_type);
|
||||
if elems > 0 {
|
||||
elems * expr_as_usize(&a.len)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
syn::Type::Path(p) => {
|
||||
if p.qself.is_none() && p.path.is_ident(slice_type) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_attr(field: &Field, attr_name: &str) -> Option<String> {
|
||||
for attr in &field.attrs {
|
||||
if let Meta::List(ml) = &attr.meta {
|
||||
if ml.path.is_ident(attr_name) {
|
||||
return Some(format!("{}", ml.tokens));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn derive_as_slice(
|
||||
input: TokenStream,
|
||||
slice_type: &str,
|
||||
attr_name: &str,
|
||||
attr_type: &str,
|
||||
) -> TokenStream {
|
||||
let DeriveInput {
|
||||
attrs, ident, data, ..
|
||||
} = parse_macro_input!(input);
|
||||
|
||||
match data {
|
||||
Data::Struct(s) => {
|
||||
let mut has_repr_c = false;
|
||||
for attr in attrs {
|
||||
match attr.meta {
|
||||
Meta::List(ml) => {
|
||||
if ml.path.is_ident("repr")
|
||||
&& format!("{}", ml.tokens) == "C"
|
||||
{
|
||||
has_repr_c = true;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
assert!(has_repr_c, "Struct must be declared #[repr(C)]");
|
||||
|
||||
let mut first = None;
|
||||
let mut count = 0_usize;
|
||||
let mut found_last = false;
|
||||
let mut attrs = TokenStream2::new();
|
||||
|
||||
if let Fields::Named(named) = s.fields {
|
||||
for f in named.named {
|
||||
let f_count = count_type(&f.ty, slice_type);
|
||||
let f_attr = get_attr(&f, &attr_name);
|
||||
|
||||
if f_count > 0 {
|
||||
assert!(
|
||||
!found_last,
|
||||
"All fields of type {slice_type} must be consecutive",
|
||||
);
|
||||
|
||||
let attr_type =
|
||||
Ident::new(attr_type, Span::call_site());
|
||||
let f_attr = if let Some(s) = f_attr {
|
||||
let s = syn::parse_str::<Ident>(&s).unwrap();
|
||||
quote! { #attr_type::#s, }
|
||||
} else {
|
||||
quote! { #attr_type::DEFAULT, }
|
||||
};
|
||||
|
||||
first.get_or_insert(f.ident);
|
||||
for _ in 0..f_count {
|
||||
attrs.extend(f_attr.clone());
|
||||
}
|
||||
count += f_count;
|
||||
} else {
|
||||
assert!(
|
||||
f_attr.is_none(),
|
||||
"{attr_name} attribute is only allowed on {slice_type}"
|
||||
);
|
||||
if !first.is_none() {
|
||||
found_last = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("Fields are not named");
|
||||
}
|
||||
|
||||
let slice_type = Ident::new(slice_type, Span::call_site());
|
||||
let attr_type = Ident::new(attr_type, Span::call_site());
|
||||
if let Some(first) = first {
|
||||
quote! {
|
||||
impl compiler::as_slice::AsSlice<#slice_type> for #ident {
|
||||
type Attr = #attr_type;
|
||||
|
||||
fn as_slice(&self) -> &[#slice_type] {
|
||||
unsafe {
|
||||
let first = &self.#first as *const #slice_type;
|
||||
std::slice::from_raw_parts(first, #count)
|
||||
}
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [#slice_type] {
|
||||
unsafe {
|
||||
let first =
|
||||
&mut self.#first as *mut #slice_type;
|
||||
std::slice::from_raw_parts_mut(first, #count)
|
||||
}
|
||||
}
|
||||
|
||||
fn attrs(&self) -> AttrList<Self::Attr> {
|
||||
static ATTRS: [#attr_type; #count] = [#attrs];
|
||||
AttrList::Array(&ATTRS)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
impl compiler::as_slice::AsSlice<#slice_type> for #ident {
|
||||
type Attr = #attr_type;
|
||||
|
||||
fn as_slice(&self) -> &[#slice_type] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [#slice_type] {
|
||||
&mut []
|
||||
}
|
||||
|
||||
fn attrs(&self) -> AttrList<Self::Attr> {
|
||||
AttrList::Uniform(#attr_type::DEFAULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Data::Enum(e) => {
|
||||
let mut as_slice_cases = TokenStream2::new();
|
||||
let mut as_mut_slice_cases = TokenStream2::new();
|
||||
let mut types_cases = TokenStream2::new();
|
||||
let slice_type = Ident::new(slice_type, Span::call_site());
|
||||
let attr_type = Ident::new(attr_type, Span::call_site());
|
||||
for v in e.variants {
|
||||
let case = v.ident;
|
||||
as_slice_cases.extend(quote! {
|
||||
#ident::#case(x) => compiler::as_slice::AsSlice::<#slice_type>::as_slice(x),
|
||||
});
|
||||
as_mut_slice_cases.extend(quote! {
|
||||
#ident::#case(x) => compiler::as_slice::AsSlice::<#slice_type>::as_mut_slice(x),
|
||||
});
|
||||
types_cases.extend(quote! {
|
||||
#ident::#case(x) => compiler::as_slice::AsSlice::<#slice_type>::attrs(x),
|
||||
});
|
||||
}
|
||||
quote! {
|
||||
impl compiler::as_slice::AsSlice<#slice_type> for #ident {
|
||||
type Attr = #attr_type;
|
||||
|
||||
fn as_slice(&self) -> &[#slice_type] {
|
||||
match self {
|
||||
#as_slice_cases
|
||||
}
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [#slice_type] {
|
||||
match self {
|
||||
#as_mut_slice_cases
|
||||
}
|
||||
}
|
||||
|
||||
fn attrs(&self) -> AttrList<Self::Attr> {
|
||||
match self {
|
||||
#types_cases
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
_ => panic!("Not a struct type"),
|
||||
}
|
||||
}
|
||||
10
src/compiler/rust/proc/lib.rs
Normal file
10
src/compiler/rust/proc/lib.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright © 2024 Collabora, Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
extern crate syn;
|
||||
|
||||
pub mod as_slice;
|
||||
|
|
@ -16,12 +16,6 @@ nak_rust_args = [
|
|||
'-Anon_snake_case',
|
||||
]
|
||||
|
||||
dep_syn = dependency('syn',
|
||||
version : '>= 2.0.15',
|
||||
fallback : ['syn', 'dep_syn'],
|
||||
required : true,
|
||||
)
|
||||
|
||||
dep_paste = dependency('paste',
|
||||
version : '>= 1.0.14',
|
||||
fallback : ['paste', 'dep_paste'],
|
||||
|
|
@ -114,7 +108,7 @@ _libnak_bindings_rs = static_library(
|
|||
_libnak_ir_proc_rs = rust.proc_macro(
|
||||
'nak_ir_proc',
|
||||
files('nak/ir_proc.rs'),
|
||||
dependencies : [dep_syn],
|
||||
dependencies : [idep_compiler_proc_rs],
|
||||
)
|
||||
|
||||
_libnak_rs = static_library(
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use nak_bindings::*;
|
|||
pub use crate::builder::{Builder, InstrBuilder, SSABuilder, SSAInstrBuilder};
|
||||
use crate::legalize::LegalizeBuilder;
|
||||
use crate::sph::{OutputTopology, PixelImap};
|
||||
use compiler::as_slice::*;
|
||||
use compiler::cfg::CFG;
|
||||
use nak_ir_proc::*;
|
||||
use std::cmp::{max, min};
|
||||
|
|
@ -1398,30 +1399,6 @@ impl fmt::Display for Src {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum AttrList<T: 'static> {
|
||||
Array(&'static [T]),
|
||||
Uniform(T),
|
||||
}
|
||||
|
||||
impl<T: 'static> Index<usize> for AttrList<T> {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, idx: usize) -> &T {
|
||||
match self {
|
||||
AttrList::Array(arr) => &arr[idx],
|
||||
AttrList::Uniform(typ) => typ,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsSlice<T> {
|
||||
type Attr;
|
||||
|
||||
fn as_slice(&self) -> &[T];
|
||||
fn as_mut_slice(&mut self) -> &mut [T];
|
||||
fn attrs(&self) -> AttrList<Self::Attr>;
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum SrcType {
|
||||
|
|
|
|||
|
|
@ -7,224 +7,11 @@ extern crate proc_macro2;
|
|||
extern crate quote;
|
||||
extern crate syn;
|
||||
|
||||
use compiler_proc::as_slice::*;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use proc_macro2::{TokenStream as TokenStream2};
|
||||
use syn::*;
|
||||
|
||||
fn expr_as_usize(expr: &syn::Expr) -> usize {
|
||||
let lit = match expr {
|
||||
syn::Expr::Lit(lit) => lit,
|
||||
_ => panic!("Expected a literal, found an expression"),
|
||||
};
|
||||
let lit_int = match &lit.lit {
|
||||
syn::Lit::Int(i) => i,
|
||||
_ => panic!("Expected a literal integer"),
|
||||
};
|
||||
assert!(lit.attrs.is_empty());
|
||||
lit_int
|
||||
.base10_parse()
|
||||
.expect("Failed to parse integer literal")
|
||||
}
|
||||
|
||||
fn count_type(ty: &Type, slice_type: &str) -> usize {
|
||||
match ty {
|
||||
syn::Type::Array(a) => {
|
||||
let elems = count_type(a.elem.as_ref(), slice_type);
|
||||
if elems > 0 {
|
||||
elems * expr_as_usize(&a.len)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
syn::Type::Path(p) => {
|
||||
if p.qself.is_none() && p.path.is_ident(slice_type) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_attr(field: &Field, attr_name: &str) -> Option<String> {
|
||||
for attr in &field.attrs {
|
||||
if let Meta::List(ml) = &attr.meta {
|
||||
if ml.path.is_ident(attr_name) {
|
||||
return Some(format!("{}", ml.tokens));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn derive_as_slice(
|
||||
input: TokenStream,
|
||||
slice_type: &str,
|
||||
attr_name: &str,
|
||||
attr_type: &str,
|
||||
) -> TokenStream {
|
||||
let DeriveInput {
|
||||
attrs, ident, data, ..
|
||||
} = parse_macro_input!(input);
|
||||
|
||||
match data {
|
||||
Data::Struct(s) => {
|
||||
let mut has_repr_c = false;
|
||||
for attr in attrs {
|
||||
match attr.meta {
|
||||
Meta::List(ml) => {
|
||||
if ml.path.is_ident("repr")
|
||||
&& format!("{}", ml.tokens) == "C"
|
||||
{
|
||||
has_repr_c = true;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
assert!(has_repr_c, "Struct must be declared #[repr(C)]");
|
||||
|
||||
let mut first = None;
|
||||
let mut count = 0_usize;
|
||||
let mut found_last = false;
|
||||
let mut attrs = TokenStream2::new();
|
||||
|
||||
if let Fields::Named(named) = s.fields {
|
||||
for f in named.named {
|
||||
let f_count = count_type(&f.ty, slice_type);
|
||||
let f_attr = get_attr(&f, &attr_name);
|
||||
|
||||
if f_count > 0 {
|
||||
assert!(
|
||||
!found_last,
|
||||
"All fields of type {slice_type} must be consecutive",
|
||||
);
|
||||
|
||||
let attr_type =
|
||||
Ident::new(attr_type, Span::call_site());
|
||||
let f_attr = if let Some(s) = f_attr {
|
||||
let s = syn::parse_str::<Ident>(&s).unwrap();
|
||||
quote! { #attr_type::#s, }
|
||||
} else {
|
||||
quote! { #attr_type::DEFAULT, }
|
||||
};
|
||||
|
||||
first.get_or_insert(f.ident);
|
||||
for _ in 0..f_count {
|
||||
attrs.extend(f_attr.clone());
|
||||
}
|
||||
count += f_count;
|
||||
} else {
|
||||
assert!(
|
||||
f_attr.is_none(),
|
||||
"{attr_name} attribute is only allowed on {slice_type}"
|
||||
);
|
||||
if !first.is_none() {
|
||||
found_last = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("Fields are not named");
|
||||
}
|
||||
|
||||
let slice_type = Ident::new(slice_type, Span::call_site());
|
||||
let attr_type = Ident::new(attr_type, Span::call_site());
|
||||
if let Some(first) = first {
|
||||
quote! {
|
||||
impl AsSlice<#slice_type> for #ident {
|
||||
type Attr = #attr_type;
|
||||
|
||||
fn as_slice(&self) -> &[#slice_type] {
|
||||
unsafe {
|
||||
let first = &self.#first as *const #slice_type;
|
||||
std::slice::from_raw_parts(first, #count)
|
||||
}
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [#slice_type] {
|
||||
unsafe {
|
||||
let first =
|
||||
&mut self.#first as *mut #slice_type;
|
||||
std::slice::from_raw_parts_mut(first, #count)
|
||||
}
|
||||
}
|
||||
|
||||
fn attrs(&self) -> AttrList<Self::Attr> {
|
||||
static ATTRS: [#attr_type; #count] = [#attrs];
|
||||
AttrList::Array(&ATTRS)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
impl AsSlice<#slice_type> for #ident {
|
||||
type Attr = #attr_type;
|
||||
|
||||
fn as_slice(&self) -> &[#slice_type] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [#slice_type] {
|
||||
&mut []
|
||||
}
|
||||
|
||||
fn attrs(&self) -> AttrList<Self::Attr> {
|
||||
AttrList::Uniform(#attr_type::DEFAULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Data::Enum(e) => {
|
||||
let mut as_slice_cases = TokenStream2::new();
|
||||
let mut as_mut_slice_cases = TokenStream2::new();
|
||||
let mut types_cases = TokenStream2::new();
|
||||
let slice_type = Ident::new(slice_type, Span::call_site());
|
||||
let attr_type = Ident::new(attr_type, Span::call_site());
|
||||
for v in e.variants {
|
||||
let case = v.ident;
|
||||
as_slice_cases.extend(quote! {
|
||||
#ident::#case(x) => AsSlice::<#slice_type>::as_slice(x),
|
||||
});
|
||||
as_mut_slice_cases.extend(quote! {
|
||||
#ident::#case(x) => AsSlice::<#slice_type>::as_mut_slice(x),
|
||||
});
|
||||
types_cases.extend(quote! {
|
||||
#ident::#case(x) => AsSlice::<#slice_type>::attrs(x),
|
||||
});
|
||||
}
|
||||
quote! {
|
||||
impl AsSlice<#slice_type> for #ident {
|
||||
type Attr = #attr_type;
|
||||
|
||||
fn as_slice(&self) -> &[#slice_type] {
|
||||
match self {
|
||||
#as_slice_cases
|
||||
}
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [#slice_type] {
|
||||
match self {
|
||||
#as_mut_slice_cases
|
||||
}
|
||||
}
|
||||
|
||||
fn attrs(&self) -> AttrList<Self::Attr> {
|
||||
match self {
|
||||
#types_cases
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
_ => panic!("Not a struct type"),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(SrcsAsSlice, attributes(src_type))]
|
||||
pub fn derive_srcs_as_slice(input: TokenStream) -> TokenStream {
|
||||
derive_as_slice(input, "Src", "src_type", "SrcType")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue