Fixes #1619: Properly bubble up errors when seeing an unexpected type during lowering.
This commit is contained in:
@@ -7,7 +7,7 @@ use crate::binemit::CodeOffset;
|
|||||||
use crate::ir::types::{B1, B16, B32, B64, B8, F32, F64, FFLAGS, I16, I32, I64, I8, IFLAGS};
|
use crate::ir::types::{B1, B16, B32, B64, B8, F32, F64, FFLAGS, I16, I32, I64, I8, IFLAGS};
|
||||||
use crate::ir::{ExternalName, Opcode, SourceLoc, TrapCode, Type};
|
use crate::ir::{ExternalName, Opcode, SourceLoc, TrapCode, Type};
|
||||||
use crate::machinst::*;
|
use crate::machinst::*;
|
||||||
use crate::settings;
|
use crate::{settings, CodegenError, CodegenResult};
|
||||||
|
|
||||||
use regalloc::Map as RegallocMap;
|
use regalloc::Map as RegallocMap;
|
||||||
use regalloc::{RealReg, RealRegUniverse, Reg, RegClass, SpillSlot, VirtualReg, Writable};
|
use regalloc::{RealReg, RealRegUniverse, Reg, RegClass, SpillSlot, VirtualReg, Writable};
|
||||||
@@ -1787,12 +1787,15 @@ impl MachInst for Inst {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rc_for_type(ty: Type) -> RegClass {
|
fn rc_for_type(ty: Type) -> CodegenResult<RegClass> {
|
||||||
match ty {
|
match ty {
|
||||||
I8 | I16 | I32 | I64 | B1 | B8 | B16 | B32 | B64 => RegClass::I64,
|
I8 | I16 | I32 | I64 | B1 | B8 | B16 | B32 | B64 => Ok(RegClass::I64),
|
||||||
F32 | F64 => RegClass::V128,
|
F32 | F64 => Ok(RegClass::V128),
|
||||||
IFLAGS | FFLAGS => RegClass::I64,
|
IFLAGS | FFLAGS => Ok(RegClass::I64),
|
||||||
_ => panic!("Unexpected SSA-value type: {}", ty),
|
_ => Err(CodegenError::Unsupported(format!(
|
||||||
|
"Unexpected SSA-value type: {}",
|
||||||
|
ty
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ impl AArch64Backend {
|
|||||||
|
|
||||||
/// This performs lowering to VCode, register-allocates the code, computes block layout and
|
/// This performs lowering to VCode, register-allocates the code, computes block layout and
|
||||||
/// finalizes branches. The result is ready for binary emission.
|
/// finalizes branches. The result is ready for binary emission.
|
||||||
fn compile_vcode(&self, func: &Function, flags: settings::Flags) -> VCode<inst::Inst> {
|
fn compile_vcode(
|
||||||
|
&self,
|
||||||
|
func: &Function,
|
||||||
|
flags: settings::Flags,
|
||||||
|
) -> CodegenResult<VCode<inst::Inst>> {
|
||||||
let abi = Box::new(abi::AArch64ABIBody::new(func, flags));
|
let abi = Box::new(abi::AArch64ABIBody::new(func, flags));
|
||||||
compile::compile::<AArch64Backend>(func, self, abi)
|
compile::compile::<AArch64Backend>(func, self, abi)
|
||||||
}
|
}
|
||||||
@@ -47,7 +51,7 @@ impl MachBackend for AArch64Backend {
|
|||||||
want_disasm: bool,
|
want_disasm: bool,
|
||||||
) -> CodegenResult<MachCompileResult> {
|
) -> CodegenResult<MachCompileResult> {
|
||||||
let flags = self.flags();
|
let flags = self.flags();
|
||||||
let vcode = self.compile_vcode(func, flags.clone());
|
let vcode = self.compile_vcode(func, flags.clone())?;
|
||||||
let sections = vcode.emit();
|
let sections = vcode.emit();
|
||||||
let frame_size = vcode.frame_size();
|
let frame_size = vcode.frame_size();
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ pub fn compile<B: LowerBackend>(
|
|||||||
f: &Function,
|
f: &Function,
|
||||||
b: &B,
|
b: &B,
|
||||||
abi: Box<dyn ABIBody<I = B::MInst>>,
|
abi: Box<dyn ABIBody<I = B::MInst>>,
|
||||||
) -> VCode<B::MInst>
|
) -> CodegenResult<VCode<B::MInst>>
|
||||||
where
|
where
|
||||||
B::MInst: ShowWithRRU,
|
B::MInst: ShowWithRRU,
|
||||||
{
|
{
|
||||||
// This lowers the CL IR.
|
// This lowers the CL IR.
|
||||||
let mut vcode = Lower::new(f, abi).lower(b);
|
let mut vcode = Lower::new(f, abi)?.lower(b)?;
|
||||||
|
|
||||||
let universe = &B::MInst::reg_universe(vcode.flags());
|
let universe = &B::MInst::reg_universe(vcode.flags());
|
||||||
|
|
||||||
@@ -62,5 +62,5 @@ where
|
|||||||
vcode.show_rru(Some(universe))
|
vcode.show_rru(Some(universe))
|
||||||
);
|
);
|
||||||
|
|
||||||
vcode
|
Ok(vcode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::ir::{
|
|||||||
MemFlags, Opcode, Signature, SourceLoc, Type, Value, ValueDef,
|
MemFlags, Opcode, Signature, SourceLoc, Type, Value, ValueDef,
|
||||||
};
|
};
|
||||||
use crate::machinst::{ABIBody, BlockIndex, VCode, VCodeBuilder, VCodeInst};
|
use crate::machinst::{ABIBody, BlockIndex, VCode, VCodeBuilder, VCodeInst};
|
||||||
use crate::num_uses::NumUses;
|
use crate::{num_uses::NumUses, CodegenResult};
|
||||||
|
|
||||||
use regalloc::{Reg, RegClass, Set, VirtualReg, Writable};
|
use regalloc::{Reg, RegClass, Set, VirtualReg, Writable};
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ enum GenerateReturn {
|
|||||||
|
|
||||||
impl<'func, I: VCodeInst> Lower<'func, I> {
|
impl<'func, I: VCodeInst> Lower<'func, I> {
|
||||||
/// Prepare a new lowering context for the given IR function.
|
/// Prepare a new lowering context for the given IR function.
|
||||||
pub fn new(f: &'func Function, abi: Box<dyn ABIBody<I = I>>) -> Lower<'func, I> {
|
pub fn new(f: &'func Function, abi: Box<dyn ABIBody<I = I>>) -> CodegenResult<Lower<'func, I>> {
|
||||||
let mut vcode = VCodeBuilder::new(abi);
|
let mut vcode = VCodeBuilder::new(abi);
|
||||||
|
|
||||||
let num_uses = NumUses::compute(f).take_uses();
|
let num_uses = NumUses::compute(f).take_uses();
|
||||||
@@ -164,7 +164,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
for param in f.dfg.block_params(bb) {
|
for param in f.dfg.block_params(bb) {
|
||||||
let vreg = alloc_vreg(
|
let vreg = alloc_vreg(
|
||||||
&mut value_regs,
|
&mut value_regs,
|
||||||
I::rc_for_type(f.dfg.value_type(*param)),
|
I::rc_for_type(f.dfg.value_type(*param))?,
|
||||||
*param,
|
*param,
|
||||||
&mut next_vreg,
|
&mut next_vreg,
|
||||||
);
|
);
|
||||||
@@ -174,7 +174,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
for result in f.dfg.inst_results(inst) {
|
for result in f.dfg.inst_results(inst) {
|
||||||
let vreg = alloc_vreg(
|
let vreg = alloc_vreg(
|
||||||
&mut value_regs,
|
&mut value_regs,
|
||||||
I::rc_for_type(f.dfg.value_type(*result)),
|
I::rc_for_type(f.dfg.value_type(*result))?,
|
||||||
*result,
|
*result,
|
||||||
&mut next_vreg,
|
&mut next_vreg,
|
||||||
);
|
);
|
||||||
@@ -188,20 +188,20 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
for ret in &f.signature.returns {
|
for ret in &f.signature.returns {
|
||||||
let v = next_vreg;
|
let v = next_vreg;
|
||||||
next_vreg += 1;
|
next_vreg += 1;
|
||||||
let regclass = I::rc_for_type(ret.value_type);
|
let regclass = I::rc_for_type(ret.value_type)?;
|
||||||
let vreg = Reg::new_virtual(regclass, v);
|
let vreg = Reg::new_virtual(regclass, v);
|
||||||
retval_regs.push((vreg, ret.extension));
|
retval_regs.push((vreg, ret.extension));
|
||||||
vcode.set_vreg_type(vreg.as_virtual_reg().unwrap(), ret.value_type);
|
vcode.set_vreg_type(vreg.as_virtual_reg().unwrap(), ret.value_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Lower {
|
Ok(Lower {
|
||||||
f,
|
f,
|
||||||
vcode,
|
vcode,
|
||||||
num_uses,
|
num_uses,
|
||||||
value_regs,
|
value_regs,
|
||||||
retval_regs,
|
retval_regs,
|
||||||
next_vreg,
|
next_vreg,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_arg_setup(&mut self) {
|
fn gen_arg_setup(&mut self) {
|
||||||
@@ -267,7 +267,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lower the function.
|
/// Lower the function.
|
||||||
pub fn lower<B: LowerBackend<MInst = I>>(mut self, backend: &B) -> VCode<I> {
|
pub fn lower<B: LowerBackend<MInst = I>>(mut self, backend: &B) -> CodegenResult<VCode<I>> {
|
||||||
// Find all reachable blocks.
|
// Find all reachable blocks.
|
||||||
let bbs = self.find_reachable_bbs();
|
let bbs = self.find_reachable_bbs();
|
||||||
|
|
||||||
@@ -421,13 +421,12 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Create a temporary for each block parameter.
|
// Create a temporary for each block parameter.
|
||||||
let phi_classes: Vec<(Type, RegClass)> = self
|
let phi_classes: Vec<Type> = self
|
||||||
.f
|
.f
|
||||||
.dfg
|
.dfg
|
||||||
.block_params(orig_block)
|
.block_params(orig_block)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| self.f.dfg.value_type(*p))
|
.map(|p| self.f.dfg.value_type(*p))
|
||||||
.map(|ty| (ty, I::rc_for_type(ty)))
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// FIXME sewardj 2020Feb29: use SmallVec
|
// FIXME sewardj 2020Feb29: use SmallVec
|
||||||
@@ -455,28 +454,27 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
if !Set::<Reg>::from_vec(src_regs.clone()).intersects(&Set::<Reg>::from_vec(
|
if !Set::<Reg>::from_vec(src_regs.clone()).intersects(&Set::<Reg>::from_vec(
|
||||||
dst_regs.iter().map(|r| r.to_reg()).collect(),
|
dst_regs.iter().map(|r| r.to_reg()).collect(),
|
||||||
)) {
|
)) {
|
||||||
for (dst_reg, (src_reg, (ty, _))) in
|
for (dst_reg, (src_reg, ty)) in
|
||||||
dst_regs.iter().zip(src_regs.iter().zip(phi_classes))
|
dst_regs.iter().zip(src_regs.iter().zip(phi_classes))
|
||||||
{
|
{
|
||||||
self.vcode.push(I::gen_move(*dst_reg, *src_reg, ty));
|
self.vcode.push(I::gen_move(*dst_reg, *src_reg, ty));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// There's some overlap, so play safe and copy via temps.
|
// There's some overlap, so play safe and copy via temps.
|
||||||
|
let mut tmp_regs = Vec::with_capacity(phi_classes.len());
|
||||||
let tmp_regs: Vec<Writable<Reg>> = phi_classes
|
for &ty in &phi_classes {
|
||||||
.iter()
|
tmp_regs.push(self.tmp(I::rc_for_type(ty)?, ty));
|
||||||
.map(|&(ty, rc)| self.tmp(rc, ty)) // borrows `self` mutably.
|
}
|
||||||
.collect();
|
|
||||||
|
|
||||||
debug!("phi_temps = {:?}", tmp_regs);
|
debug!("phi_temps = {:?}", tmp_regs);
|
||||||
debug_assert!(tmp_regs.len() == src_regs.len());
|
debug_assert!(tmp_regs.len() == src_regs.len());
|
||||||
|
|
||||||
for (tmp_reg, (src_reg, &(ty, _))) in
|
for (tmp_reg, (src_reg, &ty)) in
|
||||||
tmp_regs.iter().zip(src_regs.iter().zip(phi_classes.iter()))
|
tmp_regs.iter().zip(src_regs.iter().zip(phi_classes.iter()))
|
||||||
{
|
{
|
||||||
self.vcode.push(I::gen_move(*tmp_reg, *src_reg, ty));
|
self.vcode.push(I::gen_move(*tmp_reg, *src_reg, ty));
|
||||||
}
|
}
|
||||||
for (dst_reg, (tmp_reg, &(ty, _))) in
|
for (dst_reg, (tmp_reg, &ty)) in
|
||||||
dst_regs.iter().zip(tmp_regs.iter().zip(phi_classes.iter()))
|
dst_regs.iter().zip(tmp_regs.iter().zip(phi_classes.iter()))
|
||||||
{
|
{
|
||||||
self.vcode.push(I::gen_move(*dst_reg, tmp_reg.to_reg(), ty));
|
self.vcode.push(I::gen_move(*dst_reg, tmp_reg.to_reg(), ty));
|
||||||
@@ -495,7 +493,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now that we've emitted all instructions into the VCodeBuilder, let's build the VCode.
|
// Now that we've emitted all instructions into the VCodeBuilder, let's build the VCode.
|
||||||
self.vcode.build()
|
Ok(self.vcode.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reduce the use-count of an IR instruction. Use this when, e.g., isel incorporates the
|
/// Reduce the use-count of an IR instruction. Use this when, e.g., isel incorporates the
|
||||||
|
|||||||
@@ -163,8 +163,9 @@ pub trait MachInst: Clone + Debug {
|
|||||||
/// (e.g., add directly from or directly to memory), like x86.
|
/// (e.g., add directly from or directly to memory), like x86.
|
||||||
fn maybe_direct_reload(&self, reg: VirtualReg, slot: SpillSlot) -> Option<Self>;
|
fn maybe_direct_reload(&self, reg: VirtualReg, slot: SpillSlot) -> Option<Self>;
|
||||||
|
|
||||||
/// Determine a register class to store the given CraneLift type.
|
/// Determine a register class to store the given Cranelift type.
|
||||||
fn rc_for_type(ty: Type) -> RegClass;
|
/// May return an error if the type isn't supported by this backend.
|
||||||
|
fn rc_for_type(ty: Type) -> CodegenResult<RegClass>;
|
||||||
|
|
||||||
/// Generate a jump to another target. Used during lowering of
|
/// Generate a jump to another target. Used during lowering of
|
||||||
/// control flow.
|
/// control flow.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! Result and error types representing the outcome of compiling a function.
|
//! Result and error types representing the outcome of compiling a function.
|
||||||
|
|
||||||
use crate::verifier::VerifierErrors;
|
use crate::verifier::VerifierErrors;
|
||||||
|
use std::string::String;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// A compilation error.
|
/// A compilation error.
|
||||||
@@ -31,6 +32,12 @@ pub enum CodegenError {
|
|||||||
#[error("Code for function is too large")]
|
#[error("Code for function is too large")]
|
||||||
CodeTooLarge,
|
CodeTooLarge,
|
||||||
|
|
||||||
|
/// Something is not supported by the code generator. This might be an indication that a
|
||||||
|
/// feature is used without explicitly enabling it, or that something is temporarily
|
||||||
|
/// unsupported by a given target backend.
|
||||||
|
#[error("Unsupported feature: {0}")]
|
||||||
|
Unsupported(String),
|
||||||
|
|
||||||
/// A failure to map Cranelift register representation to a DWARF register representation.
|
/// A failure to map Cranelift register representation to a DWARF register representation.
|
||||||
#[cfg(feature = "unwind")]
|
#[cfg(feature = "unwind")]
|
||||||
#[error("Register mapping error")]
|
#[error("Register mapping error")]
|
||||||
|
|||||||
Reference in New Issue
Block a user