x64: port select to ISLE (#3682)

* x64: port `select` using an FP comparison to ISLE

This change includes quite a few interlocking parts, required mainly by
the current x64 conventions in ISLE:
 - it adds a way to emit a `cmove` with multiple OR-ing conditions;
   because x64 ISLE cannot currently safely emit a comparison followed
   by several jumps, this adds `MachInst::CmoveOr` and
   `MachInst::XmmCmoveOr` macro instructions. Unfortunately, these macro
   instructions hide the multi-instruction sequence in `lower.isle`
 - to properly keep track of what instructions consume and produce
   flags, @cfallin added a way to pass around variants of
   `ConsumesFlags` and `ProducesFlags`--these changes affect all
   backends
 - then, to lower the `fcmp + select` CLIF, this change adds several
   `cmove*_from_values` helpers that perform all of the awkward
   conversions between `Value`, `ValueReg`, `Reg`, and `Gpr/Xmm`; one
   upside is that now these lowerings have much-improved documentation
   explaining why the various `FloatCC` and `CC` choices are made the
   the way they are.

Co-authored-by: Chris Fallin <chris@cfallin.org>
This commit is contained in:
Andrew Brown
2022-02-23 10:03:16 -08:00
committed by GitHub
parent 5a5e401a9c
commit f87c61176a
20 changed files with 3163 additions and 2272 deletions

View File

@@ -6,11 +6,11 @@ use generated_code::MInst;
use regalloc::Writable;
// Types that the generated ISLE code uses via `use super::*`.
use super::{is_mergeable_load, lower_to_amode, Reg};
use super::{is_int_or_ref_ty, is_mergeable_load, lower_to_amode, Reg};
use crate::{
ir::{
immediates::*, types::*, Inst, InstructionData, Opcode, TrapCode, Value, ValueLabel,
ValueList,
condcodes::FloatCC, immediates::*, types::*, Inst, InstructionData, Opcode, TrapCode,
Value, ValueLabel, ValueList,
},
isa::{
settings::Flags,
@@ -440,6 +440,32 @@ where
fn imm8_to_imm8_gpr(&mut self, imm: u8) -> Imm8Gpr {
Imm8Gpr::new(Imm8Reg::Imm8 { imm }).unwrap()
}
fn is_gpr_type(&mut self, ty: Type) -> Option<Type> {
if is_int_or_ref_ty(ty) || ty == I128 || ty == B128 {
Some(ty)
} else {
None
}
}
#[inline]
fn is_xmm_type(&mut self, ty: Type) -> Option<Type> {
if ty == F32 || ty == F64 || (ty.is_vector() && ty.bits() == 128) {
Some(ty)
} else {
None
}
}
#[inline]
fn is_single_register_type(&mut self, ty: Type) -> Option<Type> {
if ty != I128 {
Some(ty)
} else {
None
}
}
}
// Since x64 doesn't have 8x16 shifts and we must use a 16x8 shift instead, we