s390x: Add ISLE support

This adds ISLE support for the s390x back-end and moves lowering
of most instructions to ISLE.  The only instructions still remaining
are calls, returns, traps, and branches, most of which will need
additional support in common code.

Generated code is not intended to be (significantly) different
than before; any additional optimizations now made easier to
implement due to the ISLE layer can be added in follow-on patches.

There were a few differences in some filetests, but those are all
just simple register allocation changes (and all to the better!).
This commit is contained in:
Ulrich Weigand
2022-01-20 21:46:08 +01:00
parent 2615ef967f
commit a94e72b5b7
11 changed files with 16947 additions and 3191 deletions

View File

@@ -220,6 +220,8 @@ fn get_isle_compilations(crate_dir: &std::path::Path) -> Result<IsleCompilations
make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("isa").join("x64")); make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("isa").join("x64"));
let src_isa_aarch64 = let src_isa_aarch64 =
make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("isa").join("aarch64")); make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("isa").join("aarch64"));
let src_isa_s390x =
make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("isa").join("s390x"));
// This is a set of ISLE compilation units. // This is a set of ISLE compilation units.
// //
@@ -258,6 +260,19 @@ fn get_isle_compilations(crate_dir: &std::path::Path) -> Result<IsleCompilations
src_isa_aarch64.join("lower.isle"), src_isa_aarch64.join("lower.isle"),
], ],
}, },
// The s390x instruction selector.
IsleCompilation {
output: src_isa_s390x
.join("lower")
.join("isle")
.join("generated_code.rs"),
inputs: vec![
clif_isle.clone(),
prelude_isle.clone(),
src_isa_s390x.join("inst.isle"),
src_isa_s390x.join("lower.isle"),
],
},
], ],
}) })
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,475 @@
//! ISLE integration glue code for s390x lowering.
// Pull in the ISLE generated code.
pub mod generated_code;
// Types that the generated ISLE code uses via `use super::*`.
use super::{
BranchTarget, CallIndInfo, CallInfo, Cond, Inst as MInst, JTSequenceInfo, MachLabel, MemArg,
MemFlags, Opcode, Reg, UImm16Shifted, UImm32Shifted,
};
use crate::isa::s390x::settings::Flags as IsaFlags;
use crate::machinst::isle::*;
use crate::settings::Flags;
use crate::{
ir::{
condcodes::*, immediates::*, types::*, AtomicRmwOp, Endianness, ExternalName, Inst,
InstructionData, StackSlot, TrapCode, Value, ValueLabel, ValueList,
},
isa::s390x::inst::s390x_map_regs,
isa::unwind::UnwindInst,
machinst::{InsnOutput, LowerCtx, RelocDistance},
};
use std::boxed::Box;
use std::convert::TryFrom;
use std::vec::Vec;
type BoxCallInfo = Box<CallInfo>;
type BoxCallIndInfo = Box<CallIndInfo>;
type VecMachLabel = Vec<MachLabel>;
type BoxJTSequenceInfo = Box<JTSequenceInfo>;
type BoxExternalName = Box<ExternalName>;
/// The main entry point for lowering with ISLE.
pub(crate) fn lower<C>(
lower_ctx: &mut C,
flags: &Flags,
isa_flags: &IsaFlags,
outputs: &[InsnOutput],
inst: Inst,
) -> Result<(), ()>
where
C: LowerCtx<I = MInst>,
{
lower_common(
lower_ctx,
flags,
isa_flags,
outputs,
inst,
|cx, insn| generated_code::constructor_lower(cx, insn),
s390x_map_regs,
)
}
impl<C> generated_code::Context for IsleContext<'_, C, Flags, IsaFlags, 6>
where
C: LowerCtx<I = MInst>,
{
isle_prelude_methods!();
#[inline]
fn allow_div_traps(&mut self, _: Type) -> Option<()> {
if !self.flags.avoid_div_traps() {
Some(())
} else {
None
}
}
#[inline]
fn mie2_enabled(&mut self, _: Type) -> Option<()> {
if self.isa_flags.has_mie2() {
Some(())
} else {
None
}
}
#[inline]
fn mie2_disabled(&mut self, _: Type) -> Option<()> {
if !self.isa_flags.has_mie2() {
Some(())
} else {
None
}
}
#[inline]
fn vxrs_ext2_enabled(&mut self, _: Type) -> Option<()> {
if self.isa_flags.has_vxrs_ext2() {
Some(())
} else {
None
}
}
#[inline]
fn vxrs_ext2_disabled(&mut self, _: Type) -> Option<()> {
if !self.isa_flags.has_vxrs_ext2() {
Some(())
} else {
None
}
}
#[inline]
fn symbol_value_data(&mut self, inst: Inst) -> Option<(BoxExternalName, RelocDistance, i64)> {
let (name, dist, offset) = self.lower_ctx.symbol_value(inst)?;
Some((Box::new(name.clone()), dist, offset))
}
#[inline]
fn call_target_data(&mut self, inst: Inst) -> Option<(BoxExternalName, RelocDistance)> {
let (name, dist) = self.lower_ctx.call_target(inst)?;
Some((Box::new(name.clone()), dist))
}
#[inline]
fn writable_gpr(&mut self, regno: u8) -> WritableReg {
super::writable_gpr(regno)
}
#[inline]
fn zero_reg(&mut self) -> Reg {
super::zero_reg()
}
#[inline]
fn gpr32_ty(&mut self, ty: Type) -> Option<Type> {
match ty {
I8 | I16 | I32 | B1 | B8 | B16 | B32 => Some(ty),
_ => None,
}
}
#[inline]
fn gpr64_ty(&mut self, ty: Type) -> Option<Type> {
match ty {
I64 | B64 | R64 => Some(ty),
_ => None,
}
}
#[inline]
fn uimm32shifted(&mut self, n: u32, shift: u8) -> UImm32Shifted {
UImm32Shifted::maybe_with_shift(n, shift).unwrap()
}
#[inline]
fn uimm16shifted(&mut self, n: u16, shift: u8) -> UImm16Shifted {
UImm16Shifted::maybe_with_shift(n, shift).unwrap()
}
#[inline]
fn i64_nonequal(&mut self, val: i64, cmp: i64) -> Option<i64> {
if val != cmp {
Some(val)
} else {
None
}
}
#[inline]
fn u8_as_u16(&mut self, n: u8) -> u16 {
n as u16
}
#[inline]
fn u64_as_u32(&mut self, n: u64) -> u32 {
n as u32
}
#[inline]
fn u64_as_i16(&mut self, n: u64) -> i16 {
n as i16
}
#[inline]
fn u64_nonzero_hipart(&mut self, n: u64) -> Option<u64> {
let part = n & 0xffff_ffff_0000_0000;
if part != 0 {
Some(part)
} else {
None
}
}
#[inline]
fn u64_nonzero_lopart(&mut self, n: u64) -> Option<u64> {
let part = n & 0x0000_0000_ffff_ffff;
if part != 0 {
Some(part)
} else {
None
}
}
#[inline]
fn i32_from_u64(&mut self, n: u64) -> Option<i32> {
if let Ok(imm) = i32::try_from(n as i64) {
Some(imm)
} else {
None
}
}
#[inline]
fn i16_from_u64(&mut self, n: u64) -> Option<i16> {
if let Ok(imm) = i16::try_from(n as i64) {
Some(imm)
} else {
None
}
}
#[inline]
fn uimm32shifted_from_u64(&mut self, n: u64) -> Option<UImm32Shifted> {
UImm32Shifted::maybe_from_u64(n)
}
#[inline]
fn uimm16shifted_from_u64(&mut self, n: u64) -> Option<UImm16Shifted> {
UImm16Shifted::maybe_from_u64(n)
}
#[inline]
fn u64_from_value(&mut self, val: Value) -> Option<u64> {
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
let constant = self.lower_ctx.get_constant(inst)?;
Some(constant)
}
#[inline]
fn u32_from_value(&mut self, val: Value) -> Option<u32> {
let constant = self.u64_from_value(val)?;
let imm = u32::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn u8_from_value(&mut self, val: Value) -> Option<u8> {
let constant = self.u64_from_value(val)?;
let imm = u8::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn u64_from_signed_value(&mut self, val: Value) -> Option<u64> {
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
let constant = self.lower_ctx.get_constant(inst)?;
let ty = self.lower_ctx.output_ty(inst, 0);
Some(super::sign_extend_to_u64(constant, self.ty_bits(ty)))
}
#[inline]
fn i64_from_value(&mut self, val: Value) -> Option<i64> {
let constant = self.u64_from_signed_value(val)? as i64;
Some(constant)
}
#[inline]
fn i32_from_value(&mut self, val: Value) -> Option<i32> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i32::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn i16_from_value(&mut self, val: Value) -> Option<i16> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i16::try_from(constant).ok()?;
Some(imm)
}
#[inline]
fn i16_from_swapped_value(&mut self, val: Value) -> Option<i16> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i16::try_from(constant).ok()?;
Some(imm.swap_bytes())
}
#[inline]
fn i64_from_negated_value(&mut self, val: Value) -> Option<i64> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = -constant;
Some(imm)
}
#[inline]
fn i32_from_negated_value(&mut self, val: Value) -> Option<i32> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i32::try_from(-constant).ok()?;
Some(imm)
}
#[inline]
fn i16_from_negated_value(&mut self, val: Value) -> Option<i16> {
let constant = self.u64_from_signed_value(val)? as i64;
let imm = i16::try_from(-constant).ok()?;
Some(imm)
}
#[inline]
fn uimm16shifted_from_value(&mut self, val: Value) -> Option<UImm16Shifted> {
let constant = self.u64_from_value(val)?;
UImm16Shifted::maybe_from_u64(constant)
}
#[inline]
fn uimm32shifted_from_value(&mut self, val: Value) -> Option<UImm32Shifted> {
let constant = self.u64_from_value(val)?;
UImm32Shifted::maybe_from_u64(constant)
}
#[inline]
fn uimm16shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm16Shifted> {
let constant = self.u64_from_value(val)?;
let imm = UImm16Shifted::maybe_from_u64(!constant)?;
Some(imm.negate_bits())
}
#[inline]
fn uimm32shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm32Shifted> {
let constant = self.u64_from_value(val)?;
let imm = UImm32Shifted::maybe_from_u64(!constant)?;
Some(imm.negate_bits())
}
#[inline]
fn mask_amt_imm(&mut self, ty: Type, amt: i64) -> u8 {
let mask = self.ty_bits(ty) - 1;
(amt as u8) & mask
}
#[inline]
fn mask_as_cond(&mut self, mask: u8) -> Cond {
Cond::from_mask(mask)
}
#[inline]
fn intcc_as_cond(&mut self, cc: &IntCC) -> Cond {
Cond::from_intcc(*cc)
}
#[inline]
fn floatcc_as_cond(&mut self, cc: &FloatCC) -> Cond {
Cond::from_floatcc(*cc)
}
#[inline]
fn invert_cond(&mut self, cond: &Cond) -> Cond {
Cond::invert(*cond)
}
#[inline]
fn signed(&mut self, cc: &IntCC) -> Option<()> {
if super::condcode_is_signed(*cc) {
Some(())
} else {
None
}
}
#[inline]
fn unsigned(&mut self, cc: &IntCC) -> Option<()> {
if !super::condcode_is_signed(*cc) {
Some(())
} else {
None
}
}
#[inline]
fn reloc_distance_near(&mut self, dist: &RelocDistance) -> Option<()> {
if *dist == RelocDistance::Near {
Some(())
} else {
None
}
}
#[inline]
fn zero_offset(&mut self) -> Offset32 {
Offset32::new(0)
}
#[inline]
fn i64_from_offset(&mut self, off: Offset32) -> i64 {
i64::from(off)
}
#[inline]
fn littleendian(&mut self, flags: MemFlags) -> Option<()> {
let endianness = flags.endianness(Endianness::Big);
if endianness == Endianness::Little {
Some(())
} else {
None
}
}
#[inline]
fn bigendian(&mut self, flags: MemFlags) -> Option<()> {
let endianness = flags.endianness(Endianness::Big);
if endianness == Endianness::Big {
Some(())
} else {
None
}
}
#[inline]
fn memflags_trusted(&mut self) -> MemFlags {
MemFlags::trusted()
}
#[inline]
fn memarg_reg_plus_reg(&mut self, x: Reg, y: Reg, flags: MemFlags) -> MemArg {
MemArg::reg_plus_reg(x, y, flags)
}
#[inline]
fn memarg_reg_plus_off(&mut self, reg: Reg, off: i64, flags: MemFlags) -> MemArg {
MemArg::reg_plus_off(reg, off, flags)
}
#[inline]
fn memarg_symbol(&mut self, name: BoxExternalName, offset: i32, flags: MemFlags) -> MemArg {
MemArg::Symbol {
name,
offset,
flags,
}
}
#[inline]
fn memarg_symbol_offset_sum(&mut self, off1: i64, off2: i64) -> Option<i32> {
let off = i32::try_from(off1 + off2).ok()?;
if off & 1 == 0 {
Some(off)
} else {
None
}
}
#[inline]
fn abi_stackslot_addr(
&mut self,
dst: WritableReg,
stack_slot: StackSlot,
offset: Offset32,
) -> MInst {
let offset = u32::try_from(i32::from(offset)).unwrap();
self.lower_ctx.abi().stackslot_addr(stack_slot, offset, dst)
}
#[inline]
fn sinkable_inst(&mut self, val: Value) -> Option<Inst> {
let input = self.lower_ctx.get_value_as_source_or_const(val);
if let Some((inst, 0)) = input.inst {
return Some(inst);
}
None
}
#[inline]
fn sink_inst(&mut self, inst: Inst) -> Unit {
self.lower_ctx.sink_inst(inst);
}
#[inline]
fn emit(&mut self, inst: &MInst) -> Unit {
self.emitted_insts.push(inst.clone());
}
}

View File

@@ -0,0 +1,4 @@
src/clif.isle f176ef3bba99365
src/prelude.isle 51d2aef2566c1c96
src/isa/s390x/inst.isle 63cf833b5cfd727d
src/isa/s390x/lower.isle a0e21a567040bc33

File diff suppressed because it is too large Load Diff

View File

@@ -54,8 +54,7 @@ block0(v0: i32):
; check: llgfr %r2, %r2 ; check: llgfr %r2, %r2
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lr %r2, %r0 ; nextln: ahik %r2, %r0, -32
; nextln: ahi %r2, -32
; nextln: br %r14 ; nextln: br %r14
function %clz_i16(i16) -> i16 { function %clz_i16(i16) -> i16 {
@@ -66,8 +65,7 @@ block0(v0: i16):
; check: llghr %r2, %r2 ; check: llghr %r2, %r2
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lr %r2, %r0 ; nextln: ahik %r2, %r0, -48
; nextln: ahi %r2, -48
; nextln: br %r14 ; nextln: br %r14
function %clz_i8(i8) -> i8 { function %clz_i8(i8) -> i8 {
@@ -78,8 +76,7 @@ block0(v0: i8):
; check: llgcr %r2, %r2 ; check: llgcr %r2, %r2
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lr %r2, %r0 ; nextln: ahik %r2, %r0, -56
; nextln: ahi %r2, -56
; nextln: br %r14 ; nextln: br %r14
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -93,7 +90,7 @@ block0(v0: i64):
} }
; check: srag %r3, %r2, 63 ; check: srag %r3, %r2, 63
; nextln: xgrk %r2, %r3, %r2 ; nextln: xgr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lgr %r2, %r0 ; nextln: lgr %r2, %r0
; nextln: br %r14 ; nextln: br %r14
@@ -106,10 +103,9 @@ block0(v0: i32):
; check: lgfr %r2, %r2 ; check: lgfr %r2, %r2
; nextln: srag %r3, %r2, 63 ; nextln: srag %r3, %r2, 63
; nextln: xgrk %r2, %r3, %r2 ; nextln: xgr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lr %r2, %r0 ; nextln: ahik %r2, %r0, -32
; nextln: ahi %r2, -32
; nextln: br %r14 ; nextln: br %r14
function %cls_i16(i16) -> i16 { function %cls_i16(i16) -> i16 {
@@ -120,10 +116,9 @@ block0(v0: i16):
; check: lghr %r2, %r2 ; check: lghr %r2, %r2
; nextln: srag %r3, %r2, 63 ; nextln: srag %r3, %r2, 63
; nextln: xgrk %r2, %r3, %r2 ; nextln: xgr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lr %r2, %r0 ; nextln: ahik %r2, %r0, -48
; nextln: ahi %r2, -48
; nextln: br %r14 ; nextln: br %r14
function %cls_i8(i8) -> i8 { function %cls_i8(i8) -> i8 {
@@ -134,10 +129,9 @@ block0(v0: i8):
; check: lgbr %r2, %r2 ; check: lgbr %r2, %r2
; nextln: srag %r3, %r2, 63 ; nextln: srag %r3, %r2, 63
; nextln: xgrk %r2, %r3, %r2 ; nextln: xgr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lr %r2, %r0 ; nextln: ahik %r2, %r0, -56
; nextln: ahi %r2, -56
; nextln: br %r14 ; nextln: br %r14
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -151,7 +145,7 @@ block0(v0: i64):
} }
; check: lcgr %r3, %r2 ; check: lcgr %r3, %r2
; nextln: ngrk %r2, %r3, %r2 ; nextln: ngr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: locghie %r0, -1 ; nextln: locghie %r0, -1
; nextln: lghi %r2, 63 ; nextln: lghi %r2, 63
@@ -166,7 +160,7 @@ block0(v0: i32):
; check: oihl %r2, 1 ; check: oihl %r2, 1
; nextln: lcgr %r3, %r2 ; nextln: lcgr %r3, %r2
; nextln: ngrk %r2, %r3, %r2 ; nextln: ngr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lhi %r2, 63 ; nextln: lhi %r2, 63
; nextln: sr %r2, %r0 ; nextln: sr %r2, %r0
@@ -180,7 +174,7 @@ block0(v0: i16):
; check: oilh %r2, 1 ; check: oilh %r2, 1
; nextln: lcgr %r3, %r2 ; nextln: lcgr %r3, %r2
; nextln: ngrk %r2, %r3, %r2 ; nextln: ngr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lhi %r2, 63 ; nextln: lhi %r2, 63
; nextln: sr %r2, %r0 ; nextln: sr %r2, %r0
@@ -194,7 +188,7 @@ block0(v0: i8):
; check: oill %r2, 256 ; check: oill %r2, 256
; nextln: lcgr %r3, %r2 ; nextln: lcgr %r3, %r2
; nextln: ngrk %r2, %r3, %r2 ; nextln: ngr %r2, %r3
; nextln: flogr %r0, %r2 ; nextln: flogr %r0, %r2
; nextln: lhi %r2, 63 ; nextln: lhi %r2, 63
; nextln: sr %r2, %r0 ; nextln: sr %r2, %r0

View File

@@ -13,8 +13,8 @@ block0(v0: i64, v1: i32):
; check: Block 0: ; check: Block 0:
; check: llgfr %r3, %r3 ; check: llgfr %r3, %r3
; nextln: lg %r4, 0(%r2) ; nextln: lghi %r4, 0
; nextln: aghi %r4, 0 ; nextln: ag %r4, 0(%r2)
; nextln: clgr %r3, %r4 ; nextln: clgr %r3, %r4
; nextln: jgnh label1 ; jg label2 ; nextln: jgnh label1 ; jg label2
; check: Block 1: ; check: Block 1:

View File

@@ -52,13 +52,12 @@ block0(v0: i16, v1: i16):
} }
; check: llhr %r2, %r2 ; check: llhr %r2, %r2
; nextln: lr %r3, %r4 ; nextln: lcr %r4, %r3
; nextln: lcr %r4, %r4
; nextln: nill %r3, 15 ; nextln: nill %r3, 15
; nextln: nill %r4, 15 ; nextln: nill %r4, 15
; nextln: sllk %r3, %r2, 0(%r3) ; nextln: sllk %r4, %r2, 0(%r4)
; nextln: srlk %r2, %r2, 0(%r4) ; nextln: srlk %r2, %r2, 0(%r3)
; nextln: ork %r2, %r3, %r2 ; nextln: ork %r2, %r4, %r2
; nextln: br %r14 ; nextln: br %r14
function %rotr_i16_imm(i16) -> i16 { function %rotr_i16_imm(i16) -> i16 {
@@ -81,13 +80,12 @@ block0(v0: i8, v1: i8):
} }
; check: llcr %r2, %r2 ; check: llcr %r2, %r2
; nextln: lr %r3, %r4 ; nextln: lcr %r4, %r3
; nextln: lcr %r4, %r4
; nextln: nill %r3, 7 ; nextln: nill %r3, 7
; nextln: nill %r4, 7 ; nextln: nill %r4, 7
; nextln: sllk %r3, %r2, 0(%r3) ; nextln: sllk %r4, %r2, 0(%r4)
; nextln: srlk %r2, %r2, 0(%r4) ; nextln: srlk %r2, %r2, 0(%r3)
; nextln: ork %r2, %r3, %r2 ; nextln: ork %r2, %r4, %r2
; nextln: br %r14 ; nextln: br %r14
function %rotr_i8_imm(i8) -> i8 { function %rotr_i8_imm(i8) -> i8 {
@@ -152,10 +150,9 @@ block0(v0: i16, v1: i16):
} }
; check: llhr %r2, %r2 ; check: llhr %r2, %r2
; nextln: lr %r4, %r3 ; nextln: lcr %r4, %r3
; nextln: lcr %r3, %r3
; nextln: nill %r4, 15
; nextln: nill %r3, 15 ; nextln: nill %r3, 15
; nextln: nill %r4, 15
; nextln: sllk %r3, %r2, 0(%r3) ; nextln: sllk %r3, %r2, 0(%r3)
; nextln: srlk %r2, %r2, 0(%r4) ; nextln: srlk %r2, %r2, 0(%r4)
; nextln: ork %r2, %r3, %r2 ; nextln: ork %r2, %r3, %r2
@@ -181,10 +178,9 @@ block0(v0: i8, v1: i8):
} }
; check: llcr %r2, %r2 ; check: llcr %r2, %r2
; nextln: lr %r4, %r3 ; nextln: lcr %r4, %r3
; nextln: lcr %r3, %r3
; nextln: nill %r4, 7
; nextln: nill %r3, 7 ; nextln: nill %r3, 7
; nextln: nill %r4, 7
; nextln: sllk %r3, %r2, 0(%r3) ; nextln: sllk %r3, %r2, 0(%r3)
; nextln: srlk %r2, %r2, 0(%r4) ; nextln: srlk %r2, %r2, 0(%r4)
; nextln: ork %r2, %r3, %r2 ; nextln: ork %r2, %r3, %r2