Move pass mode handling to abi/pass_mode.rs
This commit is contained in:
parent
6427eaf68b
commit
68dcfc1c78
3 changed files with 189 additions and 185 deletions
188
src/abi/mod.rs
188
src/abi/mod.rs
|
@ -1,152 +1,11 @@
|
||||||
|
mod pass_mode;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rustc::ty::layout::{FloatTy, Integer, Primitive, Scalar};
|
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use self::pass_mode::*;
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
enum PassMode {
|
|
||||||
NoPass,
|
|
||||||
ByVal(Type),
|
|
||||||
ByValPair(Type, Type),
|
|
||||||
ByRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
enum EmptySinglePair<T> {
|
|
||||||
Empty,
|
|
||||||
Single(T),
|
|
||||||
Pair(T, T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> EmptySinglePair<T> {
|
|
||||||
fn into_iter(self) -> EmptySinglePairIter<T> {
|
|
||||||
EmptySinglePairIter(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
|
|
||||||
match self {
|
|
||||||
Empty => Empty,
|
|
||||||
Single(v) => Single(f(v)),
|
|
||||||
Pair(a, b) => Pair(f(a), f(b)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct EmptySinglePairIter<T>(EmptySinglePair<T>);
|
|
||||||
|
|
||||||
impl<T> Iterator for EmptySinglePairIter<T> {
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<T> {
|
|
||||||
match std::mem::replace(&mut self.0, Empty) {
|
|
||||||
Empty => None,
|
|
||||||
Single(v) => Some(v),
|
|
||||||
Pair(a, b) => {
|
|
||||||
self.0 = Single(b);
|
|
||||||
Some(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: std::fmt::Debug> EmptySinglePair<T> {
|
|
||||||
fn assert_single(self) -> T {
|
|
||||||
match self {
|
|
||||||
Single(v) => v,
|
|
||||||
_ => panic!("Called assert_single on {:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_pair(self) -> (T, T) {
|
|
||||||
match self {
|
|
||||||
Pair(a, b) => (a, b),
|
|
||||||
_ => panic!("Called assert_pair on {:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use EmptySinglePair::*;
|
|
||||||
|
|
||||||
impl PassMode {
|
|
||||||
fn get_param_ty(self, fx: &FunctionCx<impl Backend>) -> EmptySinglePair<Type> {
|
|
||||||
match self {
|
|
||||||
PassMode::NoPass => Empty,
|
|
||||||
PassMode::ByVal(clif_type) => Single(clif_type),
|
|
||||||
PassMode::ByValPair(a, b) => Pair(a, b),
|
|
||||||
PassMode::ByRef => Single(fx.pointer_type),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scalar_to_clif_type(tcx: TyCtxt, scalar: Scalar) -> Type {
|
|
||||||
match scalar.value {
|
|
||||||
Primitive::Int(int, _sign) => match int {
|
|
||||||
Integer::I8 => types::I8,
|
|
||||||
Integer::I16 => types::I16,
|
|
||||||
Integer::I32 => types::I32,
|
|
||||||
Integer::I64 => types::I64,
|
|
||||||
Integer::I128 => types::I128,
|
|
||||||
},
|
|
||||||
Primitive::Float(flt) => match flt {
|
|
||||||
FloatTy::F32 => types::F32,
|
|
||||||
FloatTy::F64 => types::F64,
|
|
||||||
},
|
|
||||||
Primitive::Pointer => pointer_ty(tcx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pass_mode<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
layout: TyLayout<'tcx>,
|
|
||||||
) -> PassMode {
|
|
||||||
assert!(!layout.is_unsized());
|
|
||||||
|
|
||||||
if layout.is_zst() {
|
|
||||||
// WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
|
|
||||||
PassMode::NoPass
|
|
||||||
} else {
|
|
||||||
match &layout.abi {
|
|
||||||
layout::Abi::Uninhabited => PassMode::NoPass,
|
|
||||||
layout::Abi::Scalar(scalar) => {
|
|
||||||
PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone()))
|
|
||||||
}
|
|
||||||
layout::Abi::ScalarPair(a, b) => {
|
|
||||||
let a = scalar_to_clif_type(tcx, a.clone());
|
|
||||||
let b = scalar_to_clif_type(tcx, b.clone());
|
|
||||||
if a == types::I128 && b == types::I128 {
|
|
||||||
// Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
|
|
||||||
// available on x86_64. Cranelift gets confused when too many return params
|
|
||||||
// are used.
|
|
||||||
PassMode::ByRef
|
|
||||||
} else {
|
|
||||||
PassMode::ByValPair(a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME implement Vector Abi in a cg_llvm compatible way
|
|
||||||
layout::Abi::Vector { .. } => PassMode::ByRef,
|
|
||||||
|
|
||||||
layout::Abi::Aggregate { .. } => PassMode::ByRef,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn adjust_arg_for_abi<'tcx>(
|
|
||||||
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
|
||||||
arg: CValue<'tcx>,
|
|
||||||
) -> EmptySinglePair<Value> {
|
|
||||||
match get_pass_mode(fx.tcx, arg.layout()) {
|
|
||||||
PassMode::NoPass => Empty,
|
|
||||||
PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
|
|
||||||
PassMode::ByValPair(_, _) => {
|
|
||||||
let (a, b) = arg.load_scalar_pair(fx);
|
|
||||||
Pair(a, b)
|
|
||||||
}
|
|
||||||
PassMode::ByRef => Single(arg.force_stack(fx)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clif_sig_from_fn_sig<'tcx>(tcx: TyCtxt<'tcx>, sig: FnSig<'tcx>, is_vtable_fn: bool) -> Signature {
|
fn clif_sig_from_fn_sig<'tcx>(tcx: TyCtxt<'tcx>, sig: FnSig<'tcx>, is_vtable_fn: bool) -> Signature {
|
||||||
let abi = match sig.abi {
|
let abi = match sig.abi {
|
||||||
|
@ -431,47 +290,6 @@ fn local_place<'tcx>(
|
||||||
fx.local_map[&local]
|
fx.local_map[&local]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cvalue_for_param<'tcx>(
|
|
||||||
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
|
||||||
start_ebb: Ebb,
|
|
||||||
local: mir::Local,
|
|
||||||
local_field: Option<usize>,
|
|
||||||
arg_ty: Ty<'tcx>,
|
|
||||||
ssa_flags: crate::analyze::Flags,
|
|
||||||
) -> Option<CValue<'tcx>> {
|
|
||||||
let layout = fx.layout_of(arg_ty);
|
|
||||||
let pass_mode = get_pass_mode(fx.tcx, fx.layout_of(arg_ty));
|
|
||||||
|
|
||||||
if let PassMode::NoPass = pass_mode {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let clif_types = pass_mode.get_param_ty(fx);
|
|
||||||
let ebb_params = clif_types.map(|t| fx.bcx.append_ebb_param(start_ebb, t));
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
add_arg_comment(
|
|
||||||
fx,
|
|
||||||
"arg",
|
|
||||||
local,
|
|
||||||
local_field,
|
|
||||||
ebb_params,
|
|
||||||
pass_mode,
|
|
||||||
ssa_flags,
|
|
||||||
arg_ty,
|
|
||||||
);
|
|
||||||
|
|
||||||
match pass_mode {
|
|
||||||
PassMode::NoPass => unreachable!(),
|
|
||||||
PassMode::ByVal(_) => Some(CValue::by_val(ebb_params.assert_single(), layout)),
|
|
||||||
PassMode::ByValPair(_, _) => {
|
|
||||||
let (a, b) = ebb_params.assert_pair();
|
|
||||||
Some(CValue::by_val_pair(a, b, layout))
|
|
||||||
}
|
|
||||||
PassMode::ByRef => Some(CValue::by_ref(ebb_params.assert_single(), layout)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn codegen_fn_prelude(
|
pub fn codegen_fn_prelude(
|
||||||
fx: &mut FunctionCx<'_, '_, impl Backend>,
|
fx: &mut FunctionCx<'_, '_, impl Backend>,
|
||||||
start_ebb: Ebb,
|
start_ebb: Ebb,
|
||||||
|
|
168
src/abi/pass_mode.rs
Normal file
168
src/abi/pass_mode.rs
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum PassMode {
|
||||||
|
NoPass,
|
||||||
|
ByVal(Type),
|
||||||
|
ByValPair(Type, Type),
|
||||||
|
ByRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum EmptySinglePair<T> {
|
||||||
|
Empty,
|
||||||
|
Single(T),
|
||||||
|
Pair(T, T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> EmptySinglePair<T> {
|
||||||
|
pub fn into_iter(self) -> EmptySinglePairIter<T> {
|
||||||
|
EmptySinglePairIter(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
|
||||||
|
match self {
|
||||||
|
Empty => Empty,
|
||||||
|
Single(v) => Single(f(v)),
|
||||||
|
Pair(a, b) => Pair(f(a), f(b)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EmptySinglePairIter<T>(EmptySinglePair<T>);
|
||||||
|
|
||||||
|
impl<T> Iterator for EmptySinglePairIter<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<T> {
|
||||||
|
match std::mem::replace(&mut self.0, Empty) {
|
||||||
|
Empty => None,
|
||||||
|
Single(v) => Some(v),
|
||||||
|
Pair(a, b) => {
|
||||||
|
self.0 = Single(b);
|
||||||
|
Some(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: std::fmt::Debug> EmptySinglePair<T> {
|
||||||
|
pub fn assert_single(self) -> T {
|
||||||
|
match self {
|
||||||
|
Single(v) => v,
|
||||||
|
_ => panic!("Called assert_single on {:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_pair(self) -> (T, T) {
|
||||||
|
match self {
|
||||||
|
Pair(a, b) => (a, b),
|
||||||
|
_ => panic!("Called assert_pair on {:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use EmptySinglePair::*;
|
||||||
|
|
||||||
|
impl PassMode {
|
||||||
|
pub fn get_param_ty(self, fx: &FunctionCx<impl Backend>) -> EmptySinglePair<Type> {
|
||||||
|
match self {
|
||||||
|
PassMode::NoPass => Empty,
|
||||||
|
PassMode::ByVal(clif_type) => Single(clif_type),
|
||||||
|
PassMode::ByValPair(a, b) => Pair(a, b),
|
||||||
|
PassMode::ByRef => Single(fx.pointer_type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pass_mode<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
layout: TyLayout<'tcx>,
|
||||||
|
) -> PassMode {
|
||||||
|
assert!(!layout.is_unsized());
|
||||||
|
|
||||||
|
if layout.is_zst() {
|
||||||
|
// WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
|
||||||
|
PassMode::NoPass
|
||||||
|
} else {
|
||||||
|
match &layout.abi {
|
||||||
|
layout::Abi::Uninhabited => PassMode::NoPass,
|
||||||
|
layout::Abi::Scalar(scalar) => {
|
||||||
|
PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone()))
|
||||||
|
}
|
||||||
|
layout::Abi::ScalarPair(a, b) => {
|
||||||
|
let a = scalar_to_clif_type(tcx, a.clone());
|
||||||
|
let b = scalar_to_clif_type(tcx, b.clone());
|
||||||
|
if a == types::I128 && b == types::I128 {
|
||||||
|
// Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
|
||||||
|
// available on x86_64. Cranelift gets confused when too many return params
|
||||||
|
// are used.
|
||||||
|
PassMode::ByRef
|
||||||
|
} else {
|
||||||
|
PassMode::ByValPair(a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME implement Vector Abi in a cg_llvm compatible way
|
||||||
|
layout::Abi::Vector { .. } => PassMode::ByRef,
|
||||||
|
|
||||||
|
layout::Abi::Aggregate { .. } => PassMode::ByRef,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn adjust_arg_for_abi<'tcx>(
|
||||||
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
||||||
|
arg: CValue<'tcx>,
|
||||||
|
) -> EmptySinglePair<Value> {
|
||||||
|
match get_pass_mode(fx.tcx, arg.layout()) {
|
||||||
|
PassMode::NoPass => Empty,
|
||||||
|
PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
|
||||||
|
PassMode::ByValPair(_, _) => {
|
||||||
|
let (a, b) = arg.load_scalar_pair(fx);
|
||||||
|
Pair(a, b)
|
||||||
|
}
|
||||||
|
PassMode::ByRef => Single(arg.force_stack(fx)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cvalue_for_param<'tcx>(
|
||||||
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
||||||
|
start_ebb: Ebb,
|
||||||
|
local: mir::Local,
|
||||||
|
local_field: Option<usize>,
|
||||||
|
arg_ty: Ty<'tcx>,
|
||||||
|
ssa_flags: crate::analyze::Flags,
|
||||||
|
) -> Option<CValue<'tcx>> {
|
||||||
|
let layout = fx.layout_of(arg_ty);
|
||||||
|
let pass_mode = get_pass_mode(fx.tcx, fx.layout_of(arg_ty));
|
||||||
|
|
||||||
|
if let PassMode::NoPass = pass_mode {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let clif_types = pass_mode.get_param_ty(fx);
|
||||||
|
let ebb_params = clif_types.map(|t| fx.bcx.append_ebb_param(start_ebb, t));
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
super::add_arg_comment(
|
||||||
|
fx,
|
||||||
|
"arg",
|
||||||
|
local,
|
||||||
|
local_field,
|
||||||
|
ebb_params,
|
||||||
|
pass_mode,
|
||||||
|
ssa_flags,
|
||||||
|
arg_ty,
|
||||||
|
);
|
||||||
|
|
||||||
|
match pass_mode {
|
||||||
|
PassMode::NoPass => unreachable!(),
|
||||||
|
PassMode::ByVal(_) => Some(CValue::by_val(ebb_params.assert_single(), layout)),
|
||||||
|
PassMode::ByValPair(_, _) => {
|
||||||
|
let (a, b) = ebb_params.assert_pair();
|
||||||
|
Some(CValue::by_val_pair(a, b, layout))
|
||||||
|
}
|
||||||
|
PassMode::ByRef => Some(CValue::by_ref(ebb_params.assert_single(), layout)),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
use rustc::ty::layout::{FloatTy, Integer, Primitive};
|
||||||
use rustc_target::spec::{HasTargetSpec, Target};
|
use rustc_target::spec::{HasTargetSpec, Target};
|
||||||
|
|
||||||
use cranelift::codegen::ir::{Opcode, InstructionData, ValueDef};
|
use cranelift::codegen::ir::{Opcode, InstructionData, ValueDef};
|
||||||
|
@ -17,6 +18,23 @@ pub fn pointer_ty(tcx: TyCtxt) -> types::Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scalar_to_clif_type(tcx: TyCtxt, scalar: Scalar) -> Type {
|
||||||
|
match scalar.value {
|
||||||
|
Primitive::Int(int, _sign) => match int {
|
||||||
|
Integer::I8 => types::I8,
|
||||||
|
Integer::I16 => types::I16,
|
||||||
|
Integer::I32 => types::I32,
|
||||||
|
Integer::I64 => types::I64,
|
||||||
|
Integer::I128 => types::I128,
|
||||||
|
},
|
||||||
|
Primitive::Float(flt) => match flt {
|
||||||
|
FloatTy::F32 => types::F32,
|
||||||
|
FloatTy::F64 => types::F64,
|
||||||
|
},
|
||||||
|
Primitive::Pointer => pointer_ty(tcx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clif_type_from_ty<'tcx>(
|
pub fn clif_type_from_ty<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue