Skip to content

Commit 859c8af

Browse files
committed
Update generator to facilitate big endian
1 parent cf10e91 commit 859c8af

File tree

5 files changed

+558
-101
lines changed

5 files changed

+558
-101
lines changed

Diff for: crates/stdarch-gen-arm/src/big_endian.rs

+221
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
use crate::expression::LetVariant;
2+
use crate::wildstring::WildStringPart;
3+
use crate::{
4+
expression::{Expression, IdentifierType},
5+
typekinds::*,
6+
wildstring::WildString,
7+
};
8+
9+
/// Simplifies creating a string that can be used in an Expression, as Expression
10+
/// expects all strings to be `WildString`
11+
fn create_single_wild_string(name: &str) -> WildString {
12+
WildString(vec![WildStringPart::String(name.to_string())])
13+
}
14+
15+
/// Creates an Identifier with name `name` with no wildcards. This, for example,
16+
/// can be used to create variables, function names or arbitrary input. Is is
17+
/// extremely flexible.
18+
pub fn create_symbol_identifier(arbitrary_string: &str) -> Expression {
19+
let identifier_name = create_single_wild_string(arbitrary_string);
20+
Expression::Identifier(identifier_name, IdentifierType::Symbol)
21+
}
22+
23+
/// To compose the simd_shuffle! call we need:
24+
/// - simd_shuffle!(<arg1>, <arg2>, <array>)
25+
///
26+
/// Here we are creating a string version of the `<array>` that can be used as an
27+
/// Expression Identifier
28+
///
29+
/// In textual form `a: int32x4_t` which has 4 lanes would generate:
30+
/// ```
31+
/// [0, 1, 2, 3]
32+
/// ```
33+
fn create_array(lanes: u32, reverse: bool) -> Option<String> {
34+
if reverse {
35+
match lanes {
36+
1 => None, /* Makes no sense to shuffle an array of size 1 */
37+
2 => Some("[1, 0]".to_string()),
38+
3 => Some("[2, 1, 0]".to_string()),
39+
4 => Some("[3, 2, 1, 0]".to_string()),
40+
8 => Some("[7, 6, 5, 4, 3, 2, 1, 0]".to_string()),
41+
16 => Some("[15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]".to_string()),
42+
_ => panic!("Incorrect vector number of vector lanes: {}", lanes),
43+
}
44+
} else {
45+
match lanes {
46+
1 => None, /* Makes no sense to shuffle an array of size 1 */
47+
2 => Some("[0, 1]".to_string()),
48+
3 => Some("[0, 1, 2]".to_string()),
49+
4 => Some("[0, 1, 2, 3]".to_string()),
50+
8 => Some("[0, 1, 2, 3, 4, 5, 6, 7]".to_string()),
51+
16 => Some("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]".to_string()),
52+
_ => panic!("Incorrect vector number of vector lanes: {}", lanes),
53+
}
54+
}
55+
}
56+
57+
/// Creates: `let <variable_name>: <type> = <expression>`
58+
pub fn create_let_variable(
59+
variable_name: &str,
60+
type_kind: &TypeKind,
61+
expression: Expression,
62+
) -> Expression {
63+
let identifier_name = create_single_wild_string(variable_name);
64+
Expression::Let(LetVariant::WithType(
65+
identifier_name,
66+
type_kind.clone(),
67+
Box::new(expression),
68+
))
69+
}
70+
71+
pub fn create_mut_let_variable(
72+
variable_name: &str,
73+
type_kind: &TypeKind,
74+
expression: Expression,
75+
) -> Expression {
76+
let identifier_name = create_single_wild_string(variable_name);
77+
Expression::Let(LetVariant::MutWithType(
78+
identifier_name,
79+
type_kind.clone(),
80+
Box::new(expression),
81+
))
82+
}
83+
84+
pub fn type_has_tuple(type_kind: &TypeKind) -> bool {
85+
if let TypeKind::Vector(vector_type) = type_kind {
86+
vector_type.tuple_size().is_some()
87+
} else {
88+
false
89+
}
90+
}
91+
92+
pub fn make_variable_mutable(variable_name: &str, type_kind: &TypeKind) -> Expression {
93+
let mut_variable = format!(
94+
"let mut {}: {} = {}",
95+
variable_name,
96+
type_kind.to_string(),
97+
variable_name
98+
);
99+
let identifier_name = create_single_wild_string(&mut_variable);
100+
Expression::Identifier(identifier_name, IdentifierType::Symbol)
101+
}
102+
103+
/// For creating shuffle calls, accepts function pointers for formatting for tuple
104+
/// types and types without a tuple
105+
///
106+
/// Example:
107+
///
108+
/// `a: int32x4_t` with formatting function `create_shuffle_call_fmt` creates:
109+
/// ```
110+
/// simd_shuffle!(a, a, [0, 1, 2, 3])
111+
/// ```
112+
///
113+
/// `a: int32x4x2_t` creates:
114+
/// ```
115+
/// a.0 = simd_shuffle!(a.0, a.0, [0, 1, 2, 3])
116+
/// a.1 = simd_shuffle!(a.1, a.1, [0, 1, 2, 3])
117+
/// ```
118+
fn create_shuffle_internal(
119+
variable_name: &String,
120+
type_kind: &TypeKind,
121+
reverse: bool,
122+
fmt_tuple: fn(variable_name: &String, idx: u32, array_lanes: &String) -> String,
123+
fmt: fn(variable_name: &String, type_kind: &TypeKind, array_lanes: &String) -> String,
124+
) -> Option<Expression> {
125+
let TypeKind::Vector(vector_type) = type_kind else {
126+
return None;
127+
};
128+
129+
let lane_count = vector_type.lanes();
130+
let Some(array_lanes) = create_array(lane_count, reverse) else {
131+
return None;
132+
};
133+
134+
let tuple_count = vector_type.tuple_size().map_or_else(|| 0, |t| t.to_int());
135+
136+
if tuple_count > 0 {
137+
let capacity_estimate: usize =
138+
tuple_count as usize * (lane_count as usize + ((variable_name.len() + 2) * 3));
139+
let mut string_builder = String::with_capacity(capacity_estimate);
140+
141+
/* <var_name>.idx = simd_shuffle!(<var_name>.idx, <var_name>.idx, [<indexes>]) */
142+
for idx in 0..tuple_count {
143+
let formatted = fmt_tuple(variable_name, idx, &array_lanes);
144+
string_builder += formatted.as_str();
145+
}
146+
Some(create_symbol_identifier(&string_builder))
147+
} else {
148+
/* Generate a list of shuffles for each tuple */
149+
let expression = fmt(variable_name, type_kind, &array_lanes);
150+
Some(create_symbol_identifier(&expression))
151+
}
152+
}
153+
154+
fn create_assigned_tuple_shuffle_call_fmt(
155+
variable_name: &String,
156+
idx: u32,
157+
array_lanes: &String,
158+
) -> String {
159+
format!(
160+
"{variable_name}.{idx} = simd_shuffle!({variable_name}.{idx}, {variable_name}.{idx}, {array_lanes});\n",
161+
variable_name = variable_name,
162+
idx = idx,
163+
array_lanes = array_lanes
164+
)
165+
}
166+
167+
fn create_assigned_shuffle_call_fmt(
168+
variable_name: &String,
169+
type_kind: &TypeKind,
170+
array_lanes: &String,
171+
) -> String {
172+
format!(
173+
"let {variable_name}: {type_kind} = simd_shuffle!({variable_name}, {variable_name}, {array_lanes})",
174+
type_kind = type_kind.to_string(),
175+
variable_name = variable_name,
176+
array_lanes = array_lanes
177+
)
178+
}
179+
180+
fn create_shuffle_call_fmt(
181+
variable_name: &String,
182+
_type_kind: &TypeKind,
183+
array_lanes: &String,
184+
) -> String {
185+
format!(
186+
"simd_shuffle!({variable_name}, {variable_name}, {array_lanes})",
187+
variable_name = variable_name,
188+
array_lanes = array_lanes
189+
)
190+
}
191+
192+
/// Create a `simd_shuffle!(<...>, [...])` call, where the output is stored
193+
/// in a variable named `variable_name`
194+
pub fn create_assigned_shuffle_call(
195+
variable_name: &String,
196+
type_kind: &TypeKind,
197+
reverse: bool,
198+
) -> Option<Expression> {
199+
create_shuffle_internal(
200+
variable_name,
201+
type_kind,
202+
reverse,
203+
create_assigned_tuple_shuffle_call_fmt,
204+
create_assigned_shuffle_call_fmt,
205+
)
206+
}
207+
208+
/// Create a `simd_shuffle!(<...>, [...])` call
209+
pub fn create_shuffle_call(
210+
variable_name: &String,
211+
type_kind: &TypeKind,
212+
reverse: bool,
213+
) -> Option<Expression> {
214+
create_shuffle_internal(
215+
variable_name,
216+
type_kind,
217+
reverse,
218+
create_assigned_tuple_shuffle_call_fmt,
219+
create_shuffle_call_fmt,
220+
)
221+
}

Diff for: crates/stdarch-gen-arm/src/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ pub struct GlobalContext {
3535
pub arch_cfgs: Vec<ArchitectureSettings>,
3636
#[serde(default)]
3737
pub uses_neon_types: bool,
38+
39+
/// Should the yaml file automagically generate big endian shuffling
40+
#[serde(default)]
41+
pub auto_big_endian: Option<bool>,
3842
}
3943

4044
/// Context of an intrinsic group

Diff for: crates/stdarch-gen-arm/src/expression.rs

+44-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::fmt;
99
use std::str::FromStr;
1010

1111
use crate::intrinsic::Intrinsic;
12+
use crate::wildstring::WildStringPart;
1213
use crate::{
1314
context::{self, Context, VariableType},
1415
intrinsic::{Argument, LLVMLink, StaticDefinition},
@@ -29,6 +30,7 @@ pub enum IdentifierType {
2930
pub enum LetVariant {
3031
Basic(WildString, Box<Expression>),
3132
WithType(WildString, TypeKind, Box<Expression>),
33+
MutWithType(WildString, TypeKind, Box<Expression>),
3234
}
3335

3436
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -155,9 +157,11 @@ impl Expression {
155157
cl_ptr_ex.pre_build(ctx)?;
156158
arg_exs.iter_mut().try_for_each(|ex| ex.pre_build(ctx))
157159
}
158-
Self::Let(LetVariant::Basic(_, ex) | LetVariant::WithType(_, _, ex)) => {
159-
ex.pre_build(ctx)
160-
}
160+
Self::Let(
161+
LetVariant::Basic(_, ex)
162+
| LetVariant::WithType(_, _, ex)
163+
| LetVariant::MutWithType(_, _, ex),
164+
) => ex.pre_build(ctx),
161165
Self::CastAs(ex, _) => ex.pre_build(ctx),
162166
Self::Multiply(lhs, rhs) | Self::Xor(lhs, rhs) => {
163167
lhs.pre_build(ctx)?;
@@ -214,7 +218,8 @@ impl Expression {
214218
Self::Let(variant) => {
215219
let (var_name, ex, ty) = match variant {
216220
LetVariant::Basic(var_name, ex) => (var_name, ex, None),
217-
LetVariant::WithType(var_name, ty, ex) => {
221+
LetVariant::WithType(var_name, ty, ex)
222+
| LetVariant::MutWithType(var_name, ty, ex) => {
218223
if let Some(w) = ty.wildcard() {
219224
ty.populate_wildcard(ctx.local.provide_type_wildcard(w)?)?;
220225
}
@@ -285,9 +290,11 @@ impl Expression {
285290
// Nested structures that aren't inherently unsafe, but could contain other expressions
286291
// that might be.
287292
Self::Assign(_var, exp) => exp.requires_unsafe_wrapper(ctx_fn),
288-
Self::Let(LetVariant::Basic(_, exp) | LetVariant::WithType(_, _, exp)) => {
289-
exp.requires_unsafe_wrapper(ctx_fn)
290-
}
293+
Self::Let(
294+
LetVariant::Basic(_, exp)
295+
| LetVariant::WithType(_, _, exp)
296+
| LetVariant::MutWithType(_, _, exp),
297+
) => exp.requires_unsafe_wrapper(ctx_fn),
291298
Self::Array(exps) => exps.iter().any(|exp| exp.requires_unsafe_wrapper(ctx_fn)),
292299
Self::Multiply(lhs, rhs) | Self::Xor(lhs, rhs) => {
293300
lhs.requires_unsafe_wrapper(ctx_fn) || rhs.requires_unsafe_wrapper(ctx_fn)
@@ -330,6 +337,32 @@ impl Expression {
330337
}
331338
}
332339
}
340+
341+
/// Determine if an expression is a `static_assert<...>` function call.
342+
pub fn is_static_assert(&self) -> bool {
343+
match self {
344+
Expression::FnCall(fn_call) => match fn_call.0.as_ref() {
345+
Expression::Identifier(wild_string, _) => {
346+
if let WildStringPart::String(function_name) = &wild_string.0[0] {
347+
function_name.starts_with("static_assert")
348+
} else {
349+
false
350+
}
351+
}
352+
_ => panic!("Badly defined function call: {:?}", fn_call),
353+
},
354+
_ => false,
355+
}
356+
}
357+
358+
/// Determine if an espression is a LLVM binding
359+
pub fn is_llvm_link(&self) -> bool {
360+
if let Expression::LLVMLink(_) = self {
361+
true
362+
} else {
363+
false
364+
}
365+
}
333366
}
334367

335368
impl FromStr for Expression {
@@ -422,6 +455,10 @@ impl ToTokens for Expression {
422455
let var_ident = format_ident!("{}", var_name.to_string());
423456
tokens.append_all(quote! { let #var_ident: #ty = #exp })
424457
}
458+
Self::Let(LetVariant::MutWithType(var_name, ty, exp)) => {
459+
let var_ident = format_ident!("{}", var_name.to_string());
460+
tokens.append_all(quote! { let mut #var_ident: #ty = #exp })
461+
}
425462
Self::Assign(var_name, exp) => {
426463
/* If we are dereferencing a variable to assign a value \
427464
* the 'format_ident!' macro does not like the asterix */

0 commit comments

Comments
 (0)