Skip to content

Commit

Permalink
s390x: Add z14 support
Browse files Browse the repository at this point in the history
* Add support for processor features (including auto-detection).

* Move base architecture set requirement back to z14.

* Add z15 feature sets and re-enable z15-specific code generation
  when required features are available.
  • Loading branch information
uweigand committed Jun 16, 2021
1 parent 5140fd2 commit 8eddde9
Show file tree
Hide file tree
Showing 15 changed files with 892 additions and 117 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 39 additions & 2 deletions cranelift/codegen/meta/src/isa/s390x/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,50 @@ use crate::cdsl::instructions::{InstructionGroupBuilder, InstructionPredicateMap
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::recipes::Recipes;
use crate::cdsl::regs::IsaRegsBuilder;
use crate::cdsl::settings::SettingGroupBuilder;
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};

use crate::shared::Definitions as SharedDefinitions;

fn define_settings(_shared: &SettingGroup) -> SettingGroup {
let mut settings = SettingGroupBuilder::new("s390x");

// The baseline architecture for cranelift is z14 (arch12),
// so we list only facilities of later processors here.

// z15 (arch13) facilities
let has_mie2 = settings.add_bool(
"has_mie2",
"Has Miscellaneous-Instruction-Extensions Facility 2 support.",
"",
false,
);
let has_vxrs_ext2 = settings.add_bool(
"has_vxrs_ext2",
"Has Vector-Enhancements Facility 2 support.",
"",
false,
);

// Architecture level presets
settings.add_preset(
"arch13",
"Thirteenth Edition of the z/Architecture.",
preset!(has_mie2 && has_vxrs_ext2),
);

// Processor presets
settings.add_preset(
"z15",
"IBM z15 processor.",
preset!(has_mie2 && has_vxrs_ext2),
);

settings.build()
}

pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let inst_group = InstructionGroupBuilder::new(&mut shared_defs.all_instructions).build();
let settings = SettingGroupBuilder::new("s390x").build();
let settings = define_settings(&shared_defs.settings);
let regs = IsaRegsBuilder::new().build();
let recipes = Recipes::new();
let encodings_predicates = InstructionPredicateMap::new();
Expand Down
31 changes: 27 additions & 4 deletions cranelift/codegen/src/isa/s390x/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::ir::condcodes::IntCC;
use crate::ir::MemFlags;
use crate::ir::{SourceLoc, TrapCode};
use crate::isa::s390x::inst::*;
use crate::isa::s390x::settings as s390x_settings;
use core::convert::TryFrom;
use log::debug;
use regalloc::{Reg, RegClass};
Expand Down Expand Up @@ -905,17 +906,20 @@ impl EmitState {
}

/// Constant state used during function compilation.
pub struct EmitInfo(settings::Flags);
pub struct EmitInfo {
flags: settings::Flags,
isa_flags: s390x_settings::Flags,
}

impl EmitInfo {
pub(crate) fn new(flags: settings::Flags) -> Self {
Self(flags)
pub(crate) fn new(flags: settings::Flags, isa_flags: s390x_settings::Flags) -> Self {
Self { flags, isa_flags }
}
}

impl MachInstEmitInfo for EmitInfo {
fn flags(&self) -> &settings::Flags {
&self.0
&self.flags
}
}

Expand All @@ -924,6 +928,25 @@ impl MachInstEmit for Inst {
type Info = EmitInfo;

fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {
// Verify that we can emit this Inst in the current ISA
let matches_isa_flags = |iset_requirement: &InstructionSet| -> bool {
match iset_requirement {
// Baseline ISA is z14
InstructionSet::Base => true,
// Miscellaneous-Instruction-Extensions Facility 2 (z15)
InstructionSet::MIE2 => emit_info.isa_flags.has_mie2(),
// Vector-Enhancements Facility 2 (z15)
InstructionSet::VXRS_EXT2 => emit_info.isa_flags.has_vxrs_ext2(),
}
};
let isa_requirements = self.available_in_isa();
if !matches_isa_flags(&isa_requirements) {
panic!(
"Cannot emit inst '{:?}' for target; failed to match ISA requirements: {:?}",
self, isa_requirements
)
}

// N.B.: we *must* not exceed the "worst-case size" used to compute
// where to insert islands, except when islands are explicitly triggered
// (with an `EmitIsland`). We check this in debug builds. This is `mut`
Expand Down
9 changes: 8 additions & 1 deletion cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::ir::MemFlags;
use crate::isa::s390x::inst::*;
use crate::isa::s390x::settings as s390x_settings;
use crate::isa::test_utils;
use crate::settings;
use alloc::vec::Vec;
Expand Down Expand Up @@ -7767,8 +7768,14 @@ fn test_s390x_binemit() {
));

let flags = settings::Flags::new(settings::builder());

use crate::settings::Configurable;
let mut isa_flag_builder = s390x_settings::builder();
isa_flag_builder.enable("arch13").unwrap();
let isa_flags = s390x_settings::Flags::new(&flags, isa_flag_builder);

let rru = create_reg_universe(&flags);
let emit_info = EmitInfo::new(flags);
let emit_info = EmitInfo::new(flags, isa_flags);
for (insn, expected_encoding, expected_printing) in insns {
println!(
"S390x: {:?}, {}, {}",
Expand Down
170 changes: 158 additions & 12 deletions cranelift/codegen/src/isa/s390x/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ mod emit_tests;
//=============================================================================
// Instructions (top level): definition

// Supported instruction sets
#[allow(non_camel_case_types)]
#[derive(Debug)]
pub(crate) enum InstructionSet {
Base, // Baseline ISA for cranelift is z14.
MIE2, // Miscellaneous-Instruction-Extensions Facility 2 (z15)
VXRS_EXT2, // Vector-Enhancements Facility 2 (z15)
}

/// An ALU operation. This can be paired with several instruction formats
/// below (see `Inst`) in any combination.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -70,6 +79,17 @@ pub enum ALUOp {
XorNot64,
}

impl ALUOp {
pub(crate) fn available_from(&self) -> InstructionSet {
match self {
ALUOp::AndNot32 | ALUOp::AndNot64 => InstructionSet::MIE2,
ALUOp::OrrNot32 | ALUOp::OrrNot64 => InstructionSet::MIE2,
ALUOp::XorNot32 | ALUOp::XorNot64 => InstructionSet::MIE2,
_ => InstructionSet::Base,
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum UnaryOp {
Abs32,
Expand All @@ -82,6 +102,15 @@ pub enum UnaryOp {
PopcntReg,
}

impl UnaryOp {
pub(crate) fn available_from(&self) -> InstructionSet {
match self {
UnaryOp::PopcntReg => InstructionSet::MIE2,
_ => InstructionSet::Base,
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ShiftOp {
RotL32,
Expand Down Expand Up @@ -941,18 +970,6 @@ pub enum Inst {
},
}

fn count_zero_half_words(mut value: u64) -> usize {
let mut count = 0;
for _ in 0..4 {
if value & 0xffff == 0 {
count += 1;
}
value >>= 16;
}

count
}

#[test]
fn inst_size_test() {
// This test will help with unintentionally growing the size
Expand All @@ -961,6 +978,135 @@ fn inst_size_test() {
}

impl Inst {
/// Retrieve the ISA feature set in which the instruction is available.
fn available_in_isa(&self) -> InstructionSet {
match self {
// These instructions are part of the baseline ISA for cranelift (z14)
Inst::Nop0
| Inst::Nop2
| Inst::AluRRSImm16 { .. }
| Inst::AluRR { .. }
| Inst::AluRX { .. }
| Inst::AluRSImm16 { .. }
| Inst::AluRSImm32 { .. }
| Inst::AluRUImm32 { .. }
| Inst::AluRUImm16Shifted { .. }
| Inst::AluRUImm32Shifted { .. }
| Inst::ShiftRR { .. }
| Inst::SMulWide { .. }
| Inst::UMulWide { .. }
| Inst::SDivMod32 { .. }
| Inst::SDivMod64 { .. }
| Inst::UDivMod32 { .. }
| Inst::UDivMod64 { .. }
| Inst::Flogr { .. }
| Inst::CmpRR { .. }
| Inst::CmpRX { .. }
| Inst::CmpRSImm16 { .. }
| Inst::CmpRSImm32 { .. }
| Inst::CmpRUImm32 { .. }
| Inst::CmpTrapRR { .. }
| Inst::CmpTrapRSImm16 { .. }
| Inst::CmpTrapRUImm16 { .. }
| Inst::AtomicRmw { .. }
| Inst::AtomicCas32 { .. }
| Inst::AtomicCas64 { .. }
| Inst::Fence
| Inst::Load32 { .. }
| Inst::Load32ZExt8 { .. }
| Inst::Load32SExt8 { .. }
| Inst::Load32ZExt16 { .. }
| Inst::Load32SExt16 { .. }
| Inst::Load64 { .. }
| Inst::Load64ZExt8 { .. }
| Inst::Load64SExt8 { .. }
| Inst::Load64ZExt16 { .. }
| Inst::Load64SExt16 { .. }
| Inst::Load64ZExt32 { .. }
| Inst::Load64SExt32 { .. }
| Inst::LoadRev16 { .. }
| Inst::LoadRev32 { .. }
| Inst::LoadRev64 { .. }
| Inst::Store8 { .. }
| Inst::Store16 { .. }
| Inst::Store32 { .. }
| Inst::Store64 { .. }
| Inst::StoreImm8 { .. }
| Inst::StoreImm16 { .. }
| Inst::StoreImm32SExt16 { .. }
| Inst::StoreImm64SExt16 { .. }
| Inst::StoreRev16 { .. }
| Inst::StoreRev32 { .. }
| Inst::StoreRev64 { .. }
| Inst::LoadMultiple64 { .. }
| Inst::StoreMultiple64 { .. }
| Inst::Mov32 { .. }
| Inst::Mov64 { .. }
| Inst::Mov32Imm { .. }
| Inst::Mov32SImm16 { .. }
| Inst::Mov64SImm16 { .. }
| Inst::Mov64SImm32 { .. }
| Inst::Mov64UImm16Shifted { .. }
| Inst::Mov64UImm32Shifted { .. }
| Inst::Insert64UImm16Shifted { .. }
| Inst::Insert64UImm32Shifted { .. }
| Inst::Extend { .. }
| Inst::CMov32 { .. }
| Inst::CMov64 { .. }
| Inst::CMov32SImm16 { .. }
| Inst::CMov64SImm16 { .. }
| Inst::FpuMove32 { .. }
| Inst::FpuMove64 { .. }
| Inst::FpuCMov32 { .. }
| Inst::FpuCMov64 { .. }
| Inst::MovToFpr { .. }
| Inst::MovFromFpr { .. }
| Inst::FpuRR { .. }
| Inst::FpuRRR { .. }
| Inst::FpuRRRR { .. }
| Inst::FpuCopysign { .. }
| Inst::FpuCmp32 { .. }
| Inst::FpuCmp64 { .. }
| Inst::FpuLoad32 { .. }
| Inst::FpuStore32 { .. }
| Inst::FpuLoad64 { .. }
| Inst::FpuStore64 { .. }
| Inst::LoadFpuConst32 { .. }
| Inst::LoadFpuConst64 { .. }
| Inst::FpuToInt { .. }
| Inst::IntToFpu { .. }
| Inst::FpuRound { .. }
| Inst::FpuVecRRR { .. }
| Inst::Call { .. }
| Inst::CallInd { .. }
| Inst::Ret { .. }
| Inst::EpiloguePlaceholder
| Inst::Jump { .. }
| Inst::CondBr { .. }
| Inst::TrapIf { .. }
| Inst::OneWayCondBr { .. }
| Inst::IndirectBr { .. }
| Inst::Debugtrap
| Inst::Trap { .. }
| Inst::JTSequence { .. }
| Inst::LoadExtNameFar { .. }
| Inst::LoadAddr { .. }
| Inst::VirtualSPOffsetAdj { .. }
| Inst::ValueLabelMarker { .. }
| Inst::Unwind { .. } => InstructionSet::Base,

// These depend on the opcode
Inst::AluRRR { alu_op, .. } => alu_op.available_from(),
Inst::UnaryRR { op, .. } => op.available_from(),

// These are all part of VXRS_EXT2
Inst::FpuLoadRev32 { .. }
| Inst::FpuStoreRev32 { .. }
| Inst::FpuLoadRev64 { .. }
| Inst::FpuStoreRev64 { .. } => InstructionSet::VXRS_EXT2,
}
}

/// Create a 64-bit move instruction.
pub fn mov64(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {
assert!(to_reg.to_reg().get_class() == from_reg.get_class());
Expand Down
Loading

0 comments on commit 8eddde9

Please sign in to comment.