|
1 | 1 | use std::ops::Range;
|
2 | 2 |
|
3 |
| -use crate::types::IntrinsicType; |
| 3 | +use crate::types::{IntrinsicType, TypeKind}; |
4 | 4 | use crate::Language;
|
5 | 5 |
|
6 | 6 | /// An argument for the intrinsic.
|
@@ -90,49 +90,108 @@ impl ArgumentList {
|
90 | 90 | .join(", ")
|
91 | 91 | }
|
92 | 92 |
|
93 |
| - /// Creates a line that initializes this argument for C code. |
94 |
| - /// e.g. `int32x2_t a = { 0x1, 0x2 };` |
95 |
| - pub fn init_random_values_c(&self, pass: usize) -> String { |
| 93 | + /// Creates a line for each argument that initializes an array for C from which `loads` argument |
| 94 | + /// values can be loaded as a sliding window. |
| 95 | + /// e.g `const int32x2_t a_vals = {0x3effffff, 0x3effffff, 0x3f7fffff}`, if loads=2. |
| 96 | + pub fn gen_arglists_c(&self, loads: u32) -> String { |
96 | 97 | self.iter()
|
97 | 98 | .filter_map(|arg| {
|
98 | 99 | (!arg.has_constraint()).then(|| {
|
99 | 100 | format!(
|
100 |
| - "{ty} {name} = {{ {values} }};", |
101 |
| - ty = arg.to_c_type(), |
| 101 | + "const {ty} {name}_vals[] = {{ {values} }};", |
| 102 | + ty = arg.ty.c_scalar_type(), |
102 | 103 | name = arg.name,
|
103 |
| - values = arg.ty.populate_random(pass, &Language::C) |
| 104 | + values = arg.ty.populate_random(loads, &Language::C) |
104 | 105 | )
|
105 | 106 | })
|
106 | 107 | })
|
107 | 108 | .collect::<Vec<_>>()
|
108 |
| - .join("\n ") |
| 109 | + .join("\n") |
109 | 110 | }
|
110 | 111 |
|
111 |
| - /// Creates a line that initializes this argument for Rust code. |
112 |
| - /// e.g. `let a = transmute([0x1, 0x2]);` |
113 |
| - pub fn init_random_values_rust(&self, pass: usize) -> String { |
| 112 | + /// Creates a line for each argument that initializes an array for Rust from which `loads` argument |
| 113 | + /// values can be loaded as a sliding window, e.g `const A_VALS: [u32; 20] = [...];` |
| 114 | + pub fn gen_arglists_rust(&self, loads: u32) -> String { |
114 | 115 | self.iter()
|
115 | 116 | .filter_map(|arg| {
|
116 | 117 | (!arg.has_constraint()).then(|| {
|
117 |
| - if arg.is_simd() { |
118 |
| - format!( |
119 |
| - "let {name} = ::std::mem::transmute([{values}]);", |
120 |
| - name = arg.name, |
121 |
| - values = arg.ty.populate_random(pass, &Language::Rust), |
122 |
| - ) |
123 |
| - } else { |
124 |
| - format!( |
125 |
| - "let {name} = {value};", |
126 |
| - name = arg.name, |
127 |
| - value = arg.ty.populate_random(pass, &Language::Rust) |
128 |
| - ) |
129 |
| - } |
| 118 | + format!( |
| 119 | + "const {upper_name}_VALS: [{ty}; {load_size}] = unsafe{{ [{values}] }};", |
| 120 | + upper_name = arg.name.to_uppercase(), |
| 121 | + ty = arg.ty.rust_scalar_type(), |
| 122 | + load_size = arg.ty.num_lanes() * arg.ty.num_vectors() + loads - 1, |
| 123 | + values = arg.ty.populate_random(loads, &Language::Rust) |
| 124 | + ) |
| 125 | + }) |
| 126 | + }) |
| 127 | + .collect::<Vec<_>>() |
| 128 | + .join("\n") |
| 129 | + } |
| 130 | + |
| 131 | + /// Creates a line for each argument that initalizes the argument from an array [arg]_vals at |
| 132 | + /// an offset i using a load intrinsic, in C. |
| 133 | + /// e.g `uint8x8_t a = vld1_u8(&a_vals[i]);` |
| 134 | + pub fn load_values_c(&self, p64_armv7_workaround: bool) -> String { |
| 135 | + self.iter() |
| 136 | + .filter_map(|arg| { |
| 137 | + // The ACLE doesn't support 64-bit polynomial loads on Armv7 |
| 138 | + // This and the cast are a workaround for this |
| 139 | + let armv7_p64 = if let TypeKind::Poly = arg.ty.kind() { |
| 140 | + p64_armv7_workaround |
| 141 | + } else { |
| 142 | + false |
| 143 | + }; |
| 144 | + |
| 145 | + (!arg.has_constraint()).then(|| { |
| 146 | + format!( |
| 147 | + "{ty} {name} = {open_cast}{load}(&{name}_vals[i]){close_cast};", |
| 148 | + ty = arg.to_c_type(), |
| 149 | + name = arg.name, |
| 150 | + load = if arg.is_simd() { |
| 151 | + arg.ty.get_load_function(p64_armv7_workaround) |
| 152 | + } else { |
| 153 | + "*".to_string() |
| 154 | + }, |
| 155 | + open_cast = if armv7_p64 { |
| 156 | + format!("cast<{}>(", arg.to_c_type()) |
| 157 | + } else { |
| 158 | + "".to_string() |
| 159 | + }, |
| 160 | + close_cast = if armv7_p64 { |
| 161 | + ")".to_string() |
| 162 | + } else { |
| 163 | + "".to_string() |
| 164 | + } |
| 165 | + ) |
130 | 166 | })
|
131 | 167 | })
|
132 | 168 | .collect::<Vec<_>>()
|
133 | 169 | .join("\n ")
|
134 | 170 | }
|
135 | 171 |
|
| 172 | + /// Creates a line for each argument that initalizes the argument from array [ARG]_VALS at |
| 173 | + /// an offset i using a load intrinsic, in Rust. |
| 174 | + /// e.g `let a = vld1_u8(A_VALS.as_ptr().offset(i));` |
| 175 | + pub fn load_values_rust(&self) -> String { |
| 176 | + self.iter() |
| 177 | + .filter_map(|arg| { |
| 178 | + (!arg.has_constraint()).then(|| { |
| 179 | + format!( |
| 180 | + "let {name} = {load}({upper_name}_VALS.as_ptr().offset(i));", |
| 181 | + name = arg.name, |
| 182 | + upper_name = arg.name.to_uppercase(), |
| 183 | + load = if arg.is_simd() { |
| 184 | + arg.ty.get_load_function(false) |
| 185 | + } else { |
| 186 | + "*".to_string() |
| 187 | + }, |
| 188 | + ) |
| 189 | + }) |
| 190 | + }) |
| 191 | + .collect::<Vec<_>>() |
| 192 | + .join("\n ") |
| 193 | + } |
| 194 | + |
136 | 195 | pub fn iter(&self) -> std::slice::Iter<'_, Argument> {
|
137 | 196 | self.args.iter()
|
138 | 197 | }
|
|
0 commit comments