use crate::hir;
use crate::konst::*;
use crate::score::*;
use crate::ty::*;
use llhd;
use moore_common::errors::*;
use moore_common::score::Result;
use num::{Signed, ToPrimitive, Zero};
pub trait Codegen<I, C> {
fn codegen(&self, id: I, ctx: &mut C) -> Result<()>;
}
macro_rules! impl_codegen {
($slf:tt, $id:ident: $id_ty:ty, $ctx:ident: &mut $ctx_ty:ty => $blk:block) => {
impl<'lazy, 'sb, 'ast, 'ctx> Codegen<$id_ty, $ctx_ty> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn codegen(&$slf, $id: $id_ty, $ctx: &mut $ctx_ty) -> Result<()> $blk
}
};
($slf:tt, $id:ident: $id_ty:ty, $ctx:ident: &$ctx_lt:tt mut $ctx_ty:ty => $blk:block) => {
impl<'lazy, 'sb, 'ast, 'ctx, $ctx_lt> Codegen<$id_ty, $ctx_ty> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn codegen(&$slf, $id: $id_ty, $ctx: &mut $ctx_ty) -> Result<()> $blk
}
}
}
macro_rules! unimp {
($slf:tt, $id:expr) => {{
$slf.sess.emit(DiagBuilder2::bug(format!(
"code generation for {:?} not implemented",
$id
)));
return Err(());
}};
}
impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
pub fn map_type(&self, ty: &Ty) -> Result<llhd::Type> {
let ty = self.deref_named_type(ty)?;
Ok(match *ty {
Ty::Named(..) => unreachable!(),
Ty::Null => llhd::void_ty(),
Ty::Int(ref ty) => {
let diff = match ty.dir {
hir::Dir::To => &ty.right_bound - &ty.left_bound,
hir::Dir::Downto => &ty.left_bound - &ty.right_bound,
};
if diff.is_negative() {
llhd::void_ty()
} else {
llhd::int_ty(diff.bits() as usize)
}
}
Ty::Enum(ref ty) => {
let hir = self.lazy_hir(ty.decl)?;
match hir.data.as_ref().unwrap().value {
hir::TypeData::Enum(ref lits) => llhd::enum_ty(lits.len()),
_ => unreachable!(),
}
}
Ty::Physical(ref ty) => {
self.emit(DiagBuilder2::error(format!(
"cannot generate code for physical type `{}`",
ty
)));
return Err(());
}
Ty::Access(ref ty) => llhd::pointer_ty(self.map_type(ty)?),
Ty::Array(ref ty) => {
let mut llty = self.map_type(&ty.element)?;
for index in ty.indices.iter().rev() {
match *index {
ArrayIndex::Unbounded(_) => {
self.emit(
DiagBuilder2::error(format!("type `{}` is unbounded", ty)), );
return Err(());
}
ArrayIndex::Constrained(ref ty) => {
let num = match **ty {
Ty::Int(ref ty) => {
let l = ty.len();
if l.is_negative() || l.is_zero() {
return Ok(llhd::void_ty());
}
match l.to_usize() {
Some(l) => l,
None => {
self.emit(
DiagBuilder2::error(format!(
"array index `{}` is too large; {} elements",
ty, l
)), );
return Err(());
}
}
}
Ty::Enum(ref ty) => {
match self.lazy_hir(ty.decl)?.data.as_ref().unwrap().value {
hir::TypeData::Enum(ref lits) => lits.len(),
_ => unreachable!(),
}
}
_ => {
self.emit(
DiagBuilder2::error(format!(
"`{}` is an invalid array index type",
ty
)), );
return Err(());
}
};
llty = llhd::array_ty(num, llty);
}
}
}
llty
}
Ty::File(ref _ty) => llhd::int_ty(32),
Ty::Record(ref ty) => {
let fields = ty
.fields
.iter()
.map(|&(_, ref ty)| self.map_type(ty))
.collect::<Result<_>>()?;
llhd::struct_ty(fields)
}
Ty::Subprog(..) => unimplemented!(),
Ty::UnboundedInt | Ty::UniversalInt => unreachable!(),
})
}
pub fn map_const(
&self,
builder: &mut llhd::ir::UnitBuilder,
konst: &Const,
) -> Result<llhd::ir::Value> {
Ok(match *konst {
Const::Null => builder.ins().const_int((0, 0)),
Const::Int(ref k) => builder.ins().const_int((999, k.value.clone())),
Const::Enum(ref k) => {
let size = match self.lazy_hir(k.decl)?.data.as_ref().unwrap().value {
hir::TypeData::Enum(ref lits) => lits.len(),
_ => unreachable!(),
};
builder.ins().const_int((size, k.index))
}
Const::Float(ref _k) => panic!("cannot map float constant"),
Const::IntRange(_) | Const::FloatRange(_) => panic!("cannot map range constant"),
}
.into())
}
}
impl_codegen!(self, id: DeclInBlockRef, ctx: &mut llhd::ir::UnitBuilder<'_> => {
match id {
DeclInBlockRef::Subprog(id) => self.codegen(id, &mut ()),
DeclInBlockRef::SubprogBody(id) => self.codegen(id, &mut ()),
DeclInBlockRef::SubprogInst(id) => self.codegen(id, &mut ()),
DeclInBlockRef::Pkg(id) => self.codegen(id, &mut ()),
DeclInBlockRef::PkgBody(id) => self.codegen(id, &mut ()),
DeclInBlockRef::PkgInst(id) => self.codegen(id, &mut ()),
DeclInBlockRef::Type(_id) => Ok(()),
DeclInBlockRef::Subtype(_id) => Ok(()),
DeclInBlockRef::Const(id) => self.codegen(id, ctx),
DeclInBlockRef::Signal(id) => self.codegen(id, ctx),
DeclInBlockRef::Var(id) => self.codegen(id, ctx),
DeclInBlockRef::File(id) => self.codegen(id, ctx),
DeclInBlockRef::Alias(_id) => Ok(()),
DeclInBlockRef::Comp(id) => self.codegen(id, &mut ()),
DeclInBlockRef::Attr(_id) => Ok(()),
DeclInBlockRef::AttrSpec(_id) => Ok(()),
DeclInBlockRef::CfgSpec(_id) => Ok(()),
DeclInBlockRef::Discon(_id) => Ok(()),
DeclInBlockRef::GroupTemp(_id) => Ok(()),
DeclInBlockRef::Group(_id) => Ok(()),
}
});
impl_codegen!(self, id: ConstDeclRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: VarDeclRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: SignalDeclRef, ctx: &mut llhd::ir::UnitBuilder<'_> => {
let hir = self.lazy_hir(id)?;
let ty = self.lazy_typeval(id)?;
let init = if let Some(init_id) = hir.decl.init {
self.const_value(init_id)?
} else {
self.default_value_for_type(&ty)?
};
debugln!("signal {:?}, type {:?}, init {:?}", id, ty, init);
let k = self.map_const(ctx, init)?;
ctx.ins().sig(k);
Ok(())
});
impl_codegen!(self, id: FileDeclRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: ConcStmtRef, ctx: &mut llhd::ir::UnitBuilder<'_> => {
match id {
ConcStmtRef::Block(id) => self.codegen(id, ctx),
ConcStmtRef::Process(id) => self.codegen(id, ctx),
ConcStmtRef::ConcProcCall(id) => self.codegen(id, ctx),
ConcStmtRef::ConcAssert(id) => self.codegen(id, ctx),
ConcStmtRef::ConcSigAssign(id) => self.codegen(id, ctx),
ConcStmtRef::CompInst(id) => self.codegen(id, ctx),
ConcStmtRef::ForGen(id) => self.codegen(id, ctx),
ConcStmtRef::IfGen(id) => self.codegen(id, ctx),
ConcStmtRef::CaseGen(id) => self.codegen(id, ctx),
}
});
impl_codegen!(self, id: BlockStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: ProcessStmtRef, ctx: &mut llhd::ir::UnitBuilder<'_> => {
let hir = self.hir(id)?;
let name = match hir.label {
Some(n) => format!("{}_{}", ctx.name(), n.value),
None => format!("{}_proc", ctx.name()),
};
let name = llhd::ir::UnitName::Global(name);
debugln!("generating process `{}`", name);
let sig = llhd::ir::Signature::new();
let mut prok = llhd::ir::UnitData::new(llhd::ir::UnitKind::Process, name.clone(), sig.clone());
let mut prok_builder = llhd::ir::UnitBuilder::new_anonymous(&mut prok);
let entry_bb = prok_builder.named_block("entry");
prok_builder.append_to(entry_bb);
for &stmt in &hir.stmts {
self.codegen(stmt, &mut prok_builder)?;
}
let ext_unit = ctx.add_extern(
prok_builder.name().clone(),
prok_builder.sig().clone(),
);
ctx.ins().inst(ext_unit, vec![], vec![]);
self.sb.llmod.borrow_mut().add_unit(prok);
Ok(())
});
impl_codegen!(self, id: ConcCallStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: ConcAssertStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: ConcSigAssignStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: CompInstStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: ForGenStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: IfGenStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: CaseGenStmtRef, _ctx: &mut llhd::ir::UnitBuilder<'_> => {
unimp!(self, id);
});
impl_codegen!(self, id: SeqStmtRef, _ctx: &'a mut llhd::ir::UnitBuilder<'a> => {
unimp!(self, id);
});
impl_codegen!(self, id: SubprogDeclRef, _ctx: &mut () => {
unimp!(self, id);
});
impl_codegen!(self, id: SubprogBodyRef, _ctx: &mut () => {
unimp!(self, id);
});
impl_codegen!(self, id: SubprogInstRef, _ctx: &mut () => {
unimp!(self, id);
});
impl_codegen!(self, id: PkgDeclRef, _ctx: &mut () => {
unimp!(self, id);
});
impl_codegen!(self, id: PkgBodyRef, _ctx: &mut () => {
unimp!(self, id);
});
impl_codegen!(self, id: PkgInstRef, _ctx: &mut () => {
unimp!(self, id);
});
impl_codegen!(self, id: CompDeclRef, _ctx: &mut () => {
unimp!(self, id);
});