|
1 | 1 | use super::{fmtln, generate_derive, generate_derive_arbitrary_bounds, Formatter}; |
2 | 2 | use crate::dsl; |
3 | | -use crate::dsl::OperandKind; |
4 | 3 |
|
5 | 4 | impl dsl::Inst { |
6 | 5 | /// `struct <inst> { <op>: Reg, <op>: Reg, ... }` |
@@ -229,240 +228,8 @@ impl dsl::Inst { |
229 | 228 | }); |
230 | 229 | }); |
231 | 230 | } |
232 | | - |
233 | | - /// `fn x64_<inst>(&mut self, <params>) -> Inst<R> { ... }` |
234 | | - /// |
235 | | - /// # Panics |
236 | | - /// |
237 | | - /// This function panics if the instruction has no operands. |
238 | | - pub fn generate_isle_macro(&self, f: &mut Formatter) { |
239 | | - let struct_name = self.name(); |
240 | | - let params = self |
241 | | - .format |
242 | | - .operands |
243 | | - .iter() |
244 | | - .filter(|o| o.mutability.is_read()) |
245 | | - // FIXME(#10238) don't filter out fixed regs here |
246 | | - .filter(|o| !matches!(o.location.kind(), OperandKind::FixedReg(_))) |
247 | | - .collect::<Vec<_>>(); |
248 | | - let results = self |
249 | | - .format |
250 | | - .operands |
251 | | - .iter() |
252 | | - .filter(|o| o.mutability.is_write()) |
253 | | - .collect::<Vec<_>>(); |
254 | | - let rust_params = params |
255 | | - .iter() |
256 | | - .map(|o| format!("{}: {}", o.location, o.rust_param_raw())) |
257 | | - .collect::<Vec<_>>() |
258 | | - .join(", "); |
259 | | - f.add_block( |
260 | | - &format!("fn x64_{struct_name}_raw(&mut self, {rust_params}) -> AssemblerOutputs"), |
261 | | - |f| { |
262 | | - for o in params.iter() { |
263 | | - let l = o.location; |
264 | | - match o.rust_convert_isle_to_assembler() { |
265 | | - Some(cvt) => fmtln!(f, "let {l} = {cvt}({l});"), |
266 | | - None => fmtln!(f, "let {l} = {l}.clone();"), |
267 | | - } |
268 | | - } |
269 | | - let args = params |
270 | | - .iter() |
271 | | - .map(|o| format!("{}.clone()", o.location)) |
272 | | - .collect::<Vec<_>>(); |
273 | | - let args = args.join(", "); |
274 | | - fmtln!(f, "let inst = cranelift_assembler_x64::inst::{struct_name}::new({args}).into();"); |
275 | | - fmtln!(f, "let inst = MInst::External {{ inst }};"); |
276 | | - |
277 | | - use dsl::Mutability::*; |
278 | | - match results.as_slice() { |
279 | | - [] => fmtln!(f, "SideEffectNoResult::Inst(inst)"), |
280 | | - [one] => match one.mutability { |
281 | | - Read => unreachable!(), |
282 | | - ReadWrite => match one.location.kind() { |
283 | | - OperandKind::Imm(_) => unreachable!(), |
284 | | - // FIXME(#10238) |
285 | | - OperandKind::FixedReg(_) => fmtln!(f, "todo!()"), |
286 | | - // One read/write register output? Output the instruction |
287 | | - // and that register. |
288 | | - OperandKind::Reg(r) => match r.bits() { |
289 | | - 128 => { |
290 | | - fmtln!(f, "let xmm = {}.as_ref().write.to_reg();", results[0].location); |
291 | | - fmtln!(f, "AssemblerOutputs::RetXmm {{ inst, xmm }}") |
292 | | - } |
293 | | - _ => { |
294 | | - fmtln!(f, "let gpr = {}.as_ref().write.to_reg();", results[0].location); |
295 | | - fmtln!(f, "AssemblerOutputs::RetGpr {{ inst, gpr }}") |
296 | | - } |
297 | | - }, |
298 | | - // One read/write regmem output? We need to output |
299 | | - // everything and it'll internally disambiguate which was |
300 | | - // emitted (e.g. the mem variant or the register variant). |
301 | | - OperandKind::RegMem(_) => { |
302 | | - assert_eq!(results.len(), 1); |
303 | | - let l = results[0].location; |
304 | | - f.add_block(&format!("match {l}"), |f| match l.bits() { |
305 | | - 128 => { |
306 | | - f.add_block("asm::XmmMem::Xmm(reg) => ", |f| { |
307 | | - fmtln!(f, "let xmm = reg.write.to_reg();"); |
308 | | - fmtln!(f, "AssemblerOutputs::RetXmm {{ inst, xmm }} "); |
309 | | - }); |
310 | | - f.add_block("asm::XmmMem::Mem(_) => ", |f| { |
311 | | - fmtln!(f, "AssemblerOutputs::SideEffect {{ inst }} "); |
312 | | - }); |
313 | | - } |
314 | | - _ => { |
315 | | - f.add_block("asm::GprMem::Gpr(reg) => ", |f| { |
316 | | - fmtln!(f, "let gpr = reg.write.to_reg();"); |
317 | | - fmtln!(f, "AssemblerOutputs::RetGpr {{ inst, gpr }} ") |
318 | | - }); |
319 | | - f.add_block("asm::GprMem::Mem(_) => ", |f| { |
320 | | - fmtln!(f, "AssemblerOutputs::SideEffect {{ inst }} "); |
321 | | - }); |
322 | | - } |
323 | | - }); |
324 | | - } |
325 | | - }, |
326 | | - }, |
327 | | - _ => panic!("instruction has more than one result"), |
328 | | - } |
329 | | - }, |
330 | | - ); |
331 | | - } |
332 | | - |
333 | | - /// Generate a "raw" constructor that simply constructs, but does not emit |
334 | | - /// the assembly instruction: |
335 | | - /// |
336 | | - /// ```text |
337 | | - /// (decl x64_<inst>_raw (<params>) AssemblerOutputs) |
338 | | - /// (extern constructor x64_<inst>_raw x64_<inst>_raw) |
339 | | - /// ``` |
340 | | - /// |
341 | | - /// Using the "raw" constructor, we also generate "emitter" constructors |
342 | | - /// (see [`IsleConstructor`]). E.g., instructions that write to a register |
343 | | - /// will return the register: |
344 | | - /// |
345 | | - /// ```text |
346 | | - /// (decl x64_<inst> (<params>) Gpr) |
347 | | - /// (rule (x64_<inst> <params>) (emit_ret_gpr (x64_<inst>_raw <params>))) |
348 | | - /// ``` |
349 | | - /// |
350 | | - /// For instructions that write to memory, we also generate an "emitter" |
351 | | - /// constructor with the `_mem` suffix: |
352 | | - /// |
353 | | - /// ```text |
354 | | - /// (decl x64_<inst>_mem (<params>) SideEffectNoResult) |
355 | | - /// (rule (x64_<inst>_mem <params>) (defer_side_effect (x64_<inst>_raw <params>))) |
356 | | - /// ``` |
357 | | - /// |
358 | | - /// # Panics |
359 | | - /// |
360 | | - /// This function panics if the instruction has no operands. |
361 | | - pub fn generate_isle_definition(&self, f: &mut Formatter) { |
362 | | - // First declare the "raw" constructor which is implemented in Rust |
363 | | - // with `generate_isle_macro` above. This is an "extern" constructor |
364 | | - // with relatively raw types. This is not intended to be used by |
365 | | - // general lowering rules in ISLE. |
366 | | - let struct_name = self.name(); |
367 | | - let raw_name = format!("x64_{struct_name}_raw"); |
368 | | - let params = self |
369 | | - .format |
370 | | - .operands |
371 | | - .iter() |
372 | | - .filter(|o| o.mutability.is_read()) |
373 | | - // FIXME(#10238) don't filter out fixed regs here |
374 | | - .filter(|o| !matches!(o.location.kind(), OperandKind::FixedReg(_))) |
375 | | - .collect::<Vec<_>>(); |
376 | | - let raw_param_tys = params |
377 | | - .iter() |
378 | | - .map(|o| o.isle_param_raw()) |
379 | | - .collect::<Vec<_>>() |
380 | | - .join(" "); |
381 | | - fmtln!(f, "(decl {raw_name} ({raw_param_tys}) AssemblerOutputs)"); |
382 | | - fmtln!(f, "(extern constructor {raw_name} {raw_name})"); |
383 | | - |
384 | | - // Next, for each "emitter" ISLE constructor being generated, synthesize |
385 | | - // a pure-ISLE constructor which delegates appropriately to the `*_raw` |
386 | | - // constructor above. |
387 | | - // |
388 | | - // The main purpose of these constructors is to have faithful type |
389 | | - // signatures for the SSA nature of VCode/ISLE, effectively translating |
390 | | - // x64's type system to ISLE/VCode's type system. |
391 | | - for ctor in self.format.isle_constructors() { |
392 | | - let suffix = ctor.suffix(); |
393 | | - let rule_name = format!("x64_{struct_name}{suffix}"); |
394 | | - let result_ty = ctor.result_ty(); |
395 | | - let param_tys = params |
396 | | - .iter() |
397 | | - .map(|o| o.isle_param_for_ctor(ctor)) |
398 | | - .collect::<Vec<_>>() |
399 | | - .join(" "); |
400 | | - let param_names = params |
401 | | - .iter() |
402 | | - .map(|o| o.location.to_string()) |
403 | | - .collect::<Vec<_>>() |
404 | | - .join(" "); |
405 | | - let convert = ctor.conversion_constructor(); |
406 | | - |
407 | | - fmtln!(f, "(decl {rule_name} ({param_tys}) {result_ty})"); |
408 | | - fmtln!(f, "(rule ({rule_name} {param_names}) ({convert} ({raw_name} {param_names})))"); |
409 | | - } |
410 | | - } |
411 | 231 | } |
412 | 232 |
|
413 | 233 | fn comma_join<I: Into<String>>(items: impl Iterator<Item = I>) -> String { |
414 | 234 | items.map(Into::into).collect::<Vec<_>>().join(", ") |
415 | 235 | } |
416 | | - |
417 | | -/// Different kinds of ISLE constructors generated for a particular instruction. |
418 | | -/// |
419 | | -/// One instruction may generate a single constructor or multiple constructors. |
420 | | -/// For example an instruction that writes its result to a register will |
421 | | -/// generate only a single constructor. An instruction where the destination |
422 | | -/// read/write operand is `GprMem` will generate two constructors though, one |
423 | | -/// for memory and one for in registers. |
424 | | -#[derive(Copy, Clone, Debug)] |
425 | | -pub enum IsleConstructor { |
426 | | - /// This constructor only produces a side effect, meaning that the |
427 | | - /// instruction does not produce results in registers. This may produce |
428 | | - /// a result in memory, however. |
429 | | - RetMemorySideEffect, |
430 | | - |
431 | | - /// This constructor produces a `Gpr` value, meaning that it will write the |
432 | | - /// result to a `Gpr`. |
433 | | - RetGpr, |
434 | | - |
435 | | - /// This constructor produces an `Xmm` value, meaning that it will write the |
436 | | - /// result to an `Xmm`. |
437 | | - RetXmm, |
438 | | -} |
439 | | - |
440 | | -impl IsleConstructor { |
441 | | - /// Returns the result type, in ISLE, that this constructor generates. |
442 | | - pub fn result_ty(&self) -> &'static str { |
443 | | - match self { |
444 | | - IsleConstructor::RetMemorySideEffect => "SideEffectNoResult", |
445 | | - IsleConstructor::RetGpr => "Gpr", |
446 | | - IsleConstructor::RetXmm => "Xmm", |
447 | | - } |
448 | | - } |
449 | | - |
450 | | - /// Returns the constructor used to convert an `AssemblerOutput` into the |
451 | | - /// type returned by [`Self::result_ty`]. |
452 | | - pub fn conversion_constructor(&self) -> &'static str { |
453 | | - match self { |
454 | | - IsleConstructor::RetMemorySideEffect => "defer_side_effect", |
455 | | - IsleConstructor::RetGpr => "emit_ret_gpr", |
456 | | - IsleConstructor::RetXmm => "emit_ret_xmm", |
457 | | - } |
458 | | - } |
459 | | - |
460 | | - /// Returns the suffix used in the ISLE constructor name. |
461 | | - pub fn suffix(&self) -> &'static str { |
462 | | - match self { |
463 | | - IsleConstructor::RetMemorySideEffect => "_mem", |
464 | | - IsleConstructor::RetGpr => "", |
465 | | - IsleConstructor::RetXmm => "", |
466 | | - } |
467 | | - } |
468 | | -} |
0 commit comments