implement decoding shifts: s[lr][wd][.] and sra[wd][i][.]

This commit is contained in:
Jacob Lifshay 2026-01-26 15:14:26 -08:00
parent 59874b9b29
commit 1db65ae753
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
6 changed files with 11897 additions and 253 deletions

View file

@ -6,7 +6,8 @@ use crate::{
instruction::{
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
MOpRegNum, MoveRegMOp, OutputIntegerMode, StoreMOp,
MOpRegNum, MoveRegMOp, OutputIntegerMode, ShiftRotateMOp, ShiftRotateMOpImm,
ShiftRotateMode, StoreMOp,
},
powerisa_instructions_xml::{
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
@ -14,7 +15,10 @@ use crate::{
register::{
PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused,
},
util::array_vec::{ArrayVec, Length},
util::{
Rotate,
array_vec::{ArrayVec, Length},
},
};
use fayalite::{
int::{BoolOrIntType, UIntInRange},
@ -22,7 +26,10 @@ use fayalite::{
prelude::*,
ty::StaticType,
};
use std::{collections::BTreeMap, ops::RangeInclusive};
use std::{
collections::{BTreeMap, btree_map::Entry},
ops::RangeInclusive,
};
#[rustfmt::skip]
const FP_MNEMONICS: &[&str] = &[
@ -218,6 +225,10 @@ impl_fields! {
struct FieldDS(SInt<14>);
#[name = "LI"]
struct FieldLI(SInt<24>);
#[name = "SH"]
struct FieldSH(UInt<5>);
#[name = "sh"]
struct FieldSh(UInt<6>);
#[name = "SI"]
struct FieldSI(SInt<16>);
#[name = "si0"]
@ -397,6 +408,20 @@ impl DecodeState {
fields_inner: &'static InstructionBitFieldsInner,
) {
let mut last_start = word.ty().width();
struct FieldPieces {
filled_pieces: Vec<Expr<UInt>>,
piece_count: usize,
}
let mut fields_pieces = BTreeMap::new();
for bit_field in fields_inner.fields() {
fields_pieces
.entry(Self::bit_field_name(bit_field.name()))
.or_insert_with(|| FieldPieces {
filled_pieces: Vec::with_capacity(1),
piece_count: 0,
})
.piece_count += 1;
}
for bit_field in fields_inner.fields().iter().rev() {
let bit_number_text = match bit_field.bit_number().text() {
"3031" => "30 31",
@ -436,6 +461,10 @@ impl DecodeState {
if name.contains(char::is_alphabetic) {
for (cond_name, cond_value) in self.conditions() {
if name == cond_name {
assert_eq!(
fields_pieces[name].piece_count, 1,
"can't apply conditions to a field with more than one piece: name {name:?}",
);
name = cond_value;
break;
}
@ -444,15 +473,33 @@ impl DecodeState {
if name == "any value*" || name.bytes().all(|b| b == b'/') {
// wildcard
} else if name.contains(char::is_alphabetic) {
let wire = wire_with_loc(
&format!("{}_{name}", self.mnemonic)
.replace(|c: char| !c.is_ascii_alphanumeric(), "_"),
SourceLocation::caller(),
field.ty(),
);
connect(wire, field);
if fields.insert(name, wire).is_some() {
panic!("duplicate field name: {name:?}\nheader: {:#?}", self.header);
let Some(field_pieces) = fields_pieces.get_mut(name) else {
unreachable!();
};
field_pieces.filled_pieces.push(field);
if field_pieces.filled_pieces.len() == field_pieces.piece_count {
let wire = wire_with_loc(
&format!("{}_{name}", self.mnemonic)
.replace(|c: char| !c.is_ascii_alphanumeric(), "_"),
SourceLocation::caller(),
UInt[field_pieces
.filled_pieces
.iter()
.map(|v| v.ty().width())
.sum::<usize>()],
);
// filled_pieces are in lsb to msb order
let mut filled_pieces = field_pieces.filled_pieces.drain(..);
let Some(mut value) = filled_pieces.next() else {
unreachable!();
};
let mut shift = value.ty().width();
for next_value in filled_pieces {
value = value | (next_value << shift);
shift += next_value.ty().width();
}
connect(wire, value);
fields.insert(name, wire);
}
} else {
let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number");
@ -1856,6 +1903,139 @@ impl DecodeState {
);
});
}
/// for `slw[.]/srw[.]/srawi[.]/sraw[.]/sld[.]/sradi[.]/srd[.]/srad[.]`
#[hdl]
fn decode_shift(&mut self) {
let (is_32bit, is_signed, is_right_shift, is_immediate) =
match self.mnemonic.trim_end_matches('.') {
"slw" => (true, false, false, false),
"srw" => (true, false, true, false),
"srawi" => (true, true, true, true),
"sraw" => (true, true, true, false),
"sld" => (false, false, false, false),
"sradi" => (false, true, true, true),
"srd" => (false, false, true, false),
"srad" => (false, true, true, false),
_ => unreachable!("{:?}", self.mnemonic),
};
if is_immediate {
assert!(is_signed);
assert!(is_right_shift);
assert_eq!(self.arguments, Some("RA,RS,SH"));
if is_32bit {
self.decode_scope(
|this, (FieldRA(ra), FieldRS(rs), FieldSH(sh), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
ShiftRotateMOp::shift_rotate(
MOpDestReg::new(
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
[(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)],
),
[
gpr(rs).value,
MOpRegNum::const_zero().value,
MOpRegNum::const_zero().value,
],
#[hdl]
ShiftRotateMOpImm {
shift_rotate_amount: HdlSome(sh.cast_to_static::<UInt<_>>()),
shift_rotate_right: true,
dest_logic_op: HdlNone(),
},
OutputIntegerMode.Full64(),
ShiftRotateMode.SignExt32To64BitThenShift(),
),
);
},
);
} else {
self.decode_scope(
|this, (FieldRA(ra), FieldRS(rs), FieldSh(sh), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
ShiftRotateMOp::shift_rotate(
MOpDestReg::new(
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
[(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)],
),
[
gpr(rs).value,
MOpRegNum::const_zero().value,
MOpRegNum::const_zero().value,
],
#[hdl]
ShiftRotateMOpImm {
shift_rotate_amount: HdlSome(sh.rotate_right(1)),
shift_rotate_right: true,
dest_logic_op: HdlNone(),
},
OutputIntegerMode.Full64(),
ShiftRotateMode.ShiftSigned64(),
),
);
},
);
}
} else {
assert_eq!(self.arguments, Some("RA,RS,RB"));
self.decode_scope(
|this, (FieldRA(ra), FieldRS(rs), FieldRB(rb), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
ShiftRotateMOp::shift_rotate(
MOpDestReg::new(
[
gpr(ra),
if is_signed && is_right_shift {
MOpRegNum::power_isa_xer_ca_ca32_reg()
} else {
MOpRegNum::const_zero()
},
],
[(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)],
),
if !is_signed && is_right_shift {
[MOpRegNum::const_zero().value, gpr(rs).value, gpr(rb).value]
} else {
[gpr(rs).value, MOpRegNum::const_zero().value, gpr(rb).value]
},
#[hdl]
ShiftRotateMOpImm {
shift_rotate_amount: HdlNone(),
shift_rotate_right: is_right_shift,
dest_logic_op: HdlNone(),
},
OutputIntegerMode.Full64(),
match (is_32bit, is_signed, is_right_shift) {
(false, _, false) => ShiftRotateMode.FunnelShift2x64Bit(),
(false, false, true) => ShiftRotateMode.FunnelShift2x64Bit(),
(false, true, true) => ShiftRotateMode.ShiftSigned64(),
(true, _, false) => ShiftRotateMode.FunnelShift2x32Bit(),
(true, false, true) => ShiftRotateMode.FunnelShift2x32Bit(),
(true, true, true) => ShiftRotateMode.SignExt32To64BitThenShift(),
},
),
);
},
);
}
}
/// for `mcrxrx`
#[hdl]
fn decode_mcrxrx(&mut self) {
@ -2084,9 +2264,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
"slw", "slw.", "srw", "srw.", "srawi", "srawi.", "sraw", "sraw.", "sld", "sld.",
"sradi", "sradi.", "srd", "srd.", "srad", "srad.",
],
|_state| {
// TODO
},
DecodeState::decode_shift,
),
(&["extswsli", "extswsli."], |_state| {
// TODO

View file

@ -1605,17 +1605,22 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsi
#[hdl]
pub enum ShiftRotateMode {
/// like `llvm.fsh[lr].i8(src0, src1, src2)`
/// like `llvm.fsh[lr].i8(src0, src1, shift_rotate_amount.unwrap_or(src2))`
FunnelShift2x8Bit,
/// like `llvm.fsh[lr].i16(src0, src1, src2)`
/// like `llvm.fsh[lr].i16(src0, src1, shift_rotate_amount.unwrap_or(src2))`
FunnelShift2x16Bit,
/// like `llvm.fsh[lr].i32(src0, src1, src2)`
/// like `llvm.fsh[lr].i32(src0, src1, shift_rotate_amount.unwrap_or(src2))`
FunnelShift2x32Bit,
/// like `llvm.fsh[lr].i64(src0, src1, src2)`
/// like `llvm.fsh[lr].i64(src0, src1, shift_rotate_amount.unwrap_or(src2))`
FunnelShift2x64Bit,
/// `shift(src0 as i8 as i64, shift_rotate_amount.unwrap_or(src2))`
SignExt8To64BitThenShift,
/// `shift(src0 as i16 as i64, shift_rotate_amount.unwrap_or(src2))`
SignExt16To64BitThenShift,
/// `shift(src0 as i32 as i64, shift_rotate_amount.unwrap_or(src2))`
SignExt32To64BitThenShift,
/// `shift(src0 as i64, shift_rotate_amount.unwrap_or(src2))`
ShiftSigned64,
}
impl HdlPartialEqImpl<Self> for ShiftRotateMode {

View file

@ -38,6 +38,54 @@ pub trait Rotate<Amount> {
fn rotate_right(&self, amount: Amount) -> Self::Output;
}
impl<VSz: Size> Rotate<usize> for Expr<UIntType<VSz>> {
type Output = Self;
/// like [`usize::rotate_left`]
fn rotate_left(&self, amount: usize) -> Self::Output {
if self.ty().width() == 0 {
return *self;
}
let amount = amount % self.ty().width();
let l = *self << amount;
let r = *self >> (self.ty().width() - amount);
(l | r).cast_to(self.ty())
}
/// like [`usize::rotate_right`]
fn rotate_right(&self, amount: usize) -> Self::Output {
if self.ty().width() == 0 {
return *self;
}
let amount = amount % self.ty().width();
let l = *self << (self.ty().width() - amount);
let r = *self >> amount;
(l | r).cast_to(self.ty())
}
}
impl<VSz: Size> Rotate<usize> for SimValue<UIntType<VSz>> {
type Output = Self;
/// like [`usize::rotate_left`]
fn rotate_left(&self, amount: usize) -> Self::Output {
if self.ty().width() == 0 {
return self.clone();
}
let amount = amount % self.ty().width();
let l = self << amount;
let r = self >> (self.ty().width() - amount);
(l | r).cast_to(self.ty())
}
/// like [`usize::rotate_right`]
fn rotate_right(&self, amount: usize) -> Self::Output {
if self.ty().width() == 0 {
return self.clone();
}
let amount = amount % self.ty().width();
let l = self << (self.ty().width() - amount);
let r = self >> amount;
(l | r).cast_to(self.ty())
}
}
impl<VSz: Size, ASz: Size> Rotate<Expr<UIntType<ASz>>> for Expr<UIntType<VSz>> {
type Output = Self;
/// like [`usize::rotate_left`]
@ -176,3 +224,59 @@ impl<T: Type, N: Size, AmountSize: Size> Rotate<SimValue<UIntType<AmountSize>>>
retval
}
}
impl<T: Type, N: Size> Rotate<usize> for Expr<ArrayType<T, N>> {
type Output = Self;
/// like [`<[T]>::rotate_left`](slice::rotate_left)
fn rotate_left(&self, amount: usize) -> Self::Output {
if self.ty().len() == 0 {
return self.clone();
}
let amount = amount % self.ty().len();
let mut retval = Vec::from_iter(*self);
retval.rotate_left(amount);
ArrayLiteral::new(
self.ty().element(),
retval.into_iter().map(Expr::canonical).collect(),
)
.to_expr()
}
/// like [`<[T]>::rotate_right`](slice::rotate_right)
fn rotate_right(&self, amount: usize) -> Self::Output {
if self.ty().len() == 0 {
return self.clone();
}
let amount = amount % self.ty().len();
let mut retval = Vec::from_iter(*self);
retval.rotate_right(amount);
ArrayLiteral::new(
self.ty().element(),
retval.into_iter().map(Expr::canonical).collect(),
)
.to_expr()
}
}
impl<T: Type, N: Size> Rotate<usize> for SimValue<ArrayType<T, N>> {
type Output = Self;
/// like [`<[T]>::rotate_left`](slice::rotate_left)
fn rotate_left(&self, amount: usize) -> Self::Output {
if self.ty().len() == 0 {
return self.clone();
}
let amount = amount % self.ty().len();
let mut retval = self.clone();
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_left(amount);
retval
}
/// like [`<[T]>::rotate_right`](slice::rotate_right)
fn rotate_right(&self, amount: usize) -> Self::Output {
if self.ty().len() == 0 {
return self.clone();
}
let amount = amount % self.ty().len();
let mut retval = self.clone();
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_right(amount);
retval
}
}

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@ mod fixed_point_arithmetic;
mod fixed_point_compare;
mod fixed_point_load;
mod fixed_point_logical;
mod fixed_point_rotate_and_shift;
mod fixed_point_store;
mod move_to_from_system_register;
mod prefixed_no_operation;
@ -143,6 +144,9 @@ pub fn test_cases() -> Vec<TestCase> {
fixed_point_arithmetic::test_cases_book_i_3_3_9_fixed_point_arithmetic(&mut retval);
fixed_point_compare::test_cases_book_i_3_3_10_fixed_point_compare(&mut retval);
fixed_point_logical::test_cases_book_i_3_3_13_fixed_point_logical(&mut retval);
fixed_point_rotate_and_shift::test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(
&mut retval,
);
move_to_from_system_register::test_cases_book_i_3_3_19_move_to_from_system_register(
&mut retval,
);

View file

@ -0,0 +1,364 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::test_cases::{TestCase, insn_single};
use cpu::instruction::{
AddSubMOp, MOpDestReg, MOpRegNum, OutputIntegerMode, ShiftRotateMOp, ShiftRotateMOpImm,
ShiftRotateMode,
};
use fayalite::prelude::*;
#[hdl]
fn shift_imm(amount: Option<u8>, shift_right: bool) -> Expr<ShiftRotateMOpImm> {
#[hdl]
ShiftRotateMOpImm {
shift_rotate_amount: if let Some(amount) = amount {
HdlSome(amount.cast_to_static::<UInt<_>>())
} else {
HdlNone()
},
shift_rotate_right: shift_right,
dest_logic_op: HdlNone(),
}
}
/// covers instructions in PowerISA v3.1C Book I 3.3.14 Fixed-Point Rotate and Shift Instructions
pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<TestCase>) {
// TODO: rotate instructions
macro_rules! shift_left {
(
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
$encoding:literal;
$shift_rotate_mode:ident;
) => {{
retval.push(insn_single(
concat!(
$mnemonic,
" ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
[
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::const_zero().value,
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
],
shift_imm(None, false),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
retval.push(insn_single(
concat!(
$mnemonic,
". ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding | 1,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::const_zero().value,
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
],
shift_imm(None, false),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
}};
}
macro_rules! shift_right_unsigned {
(
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
$encoding:literal;
$shift_rotate_mode:ident;
) => {{
retval.push(insn_single(
concat!(
$mnemonic,
" ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
[
MOpRegNum::const_zero().value,
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
],
shift_imm(None, true),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
retval.push(insn_single(
concat!(
$mnemonic,
". ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding | 1,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::const_zero().value,
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
],
shift_imm(None, true),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
}};
}
macro_rules! shift_right_signed {
(
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
$encoding:literal;
$shift_rotate_mode:ident;
) => {{
retval.push(insn_single(
concat!(
$mnemonic,
" ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::const_zero().value,
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
],
shift_imm(None, true),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
retval.push(insn_single(
concat!(
$mnemonic,
". ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding | 1,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::const_zero().value,
MOpRegNum::power_isa_gpr_reg_imm($amount).value,
],
shift_imm(None, true),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
}};
}
macro_rules! shift_right_signed_imm {
(
$mnemonic:literal $dest:literal, $src:literal, $amount:literal;
$encoding:literal;
$shift_rotate_mode:ident;
) => {{
retval.push(insn_single(
concat!(
$mnemonic,
" ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::const_zero().value,
MOpRegNum::const_zero().value,
],
shift_imm(Some($amount), true),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
retval.push(insn_single(
concat!(
$mnemonic,
". ",
stringify!($dest),
", ",
stringify!($src),
", ",
stringify!($amount)
),
$encoding | 1,
None,
ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src).value,
MOpRegNum::const_zero().value,
MOpRegNum::const_zero().value,
],
shift_imm(Some($amount), true),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
));
}};
}
shift_left! {
"slw" 3, 4, 5;
0x7c832830;
FunnelShift2x32Bit;
}
shift_right_unsigned! {
"srw" 3, 4, 5;
0x7c832c30;
FunnelShift2x32Bit;
}
shift_right_signed_imm! {
"srawi" 3, 4, 0;
0x7c830670;
SignExt32To64BitThenShift;
}
shift_right_signed_imm! {
"srawi" 3, 4, 5;
0x7c832e70;
SignExt32To64BitThenShift;
}
shift_right_signed_imm! {
"srawi" 3, 4, 16;
0x7c838670;
SignExt32To64BitThenShift;
}
shift_right_signed_imm! {
"srawi" 3, 4, 31;
0x7c83fe70;
SignExt32To64BitThenShift;
}
shift_right_signed! {
"sraw" 3, 4, 5;
0x7c832e30;
SignExt32To64BitThenShift;
}
shift_left! {
"sld" 3, 4, 5;
0x7c832836;
FunnelShift2x64Bit;
}
shift_right_unsigned! {
"srd" 3, 4, 5;
0x7c832c36;
FunnelShift2x64Bit;
}
shift_right_signed_imm! {
"sradi" 3, 4, 0;
0x7c830674;
ShiftSigned64;
}
shift_right_signed_imm! {
"sradi" 3, 4, 5;
0x7c832e74;
ShiftSigned64;
}
shift_right_signed_imm! {
"sradi" 3, 4, 16;
0x7c838674;
ShiftSigned64;
}
shift_right_signed_imm! {
"sradi" 3, 4, 31;
0x7c83fe74;
ShiftSigned64;
}
shift_right_signed_imm! {
"sradi" 3, 4, 32;
0x7c830676;
ShiftSigned64;
}
shift_right_signed_imm! {
"sradi" 3, 4, 63;
0x7c83fe76;
ShiftSigned64;
}
shift_right_signed! {
"srad" 3, 4, 5;
0x7c832e34;
ShiftSigned64;
}
// TODO: extswsli
}