use orzir_core::{verify_error, Context, Op, Ty, VerifyResult};
use thiserror::Error;
pub mod control_flow;
#[derive(Debug, Error)]
#[error("operand is not isolated from above")]
struct NotIsolatedFromAboveError;
pub trait IsIsolatedFromAbove: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
let mut pending_regions = Vec::new();
for region in self.regions() {
pending_regions.push(region);
while !pending_regions.is_empty() {
let pending_region = pending_regions.pop().unwrap().deref(&ctx.regions);
for block in pending_region.layout().iter() {
for op in block.deref(&ctx.blocks).layout().iter() {
for operand in op.deref(&ctx.ops).as_ref().operands() {
let operand_region = operand.deref(&ctx.values).parent_region(ctx);
if !region.deref(&ctx.regions).is_ancestor(ctx, operand_region) {
return verify_error!(NotIsolatedFromAboveError).into();
}
}
if !op.deref(&ctx.ops).as_ref().regions().is_empty()
&& !op.deref(&ctx.ops).impls::<dyn IsIsolatedFromAbove>(ctx)
{
for sub_region in op.deref(&ctx.ops).as_ref().regions() {
pending_regions.push(sub_region);
}
}
}
}
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of results: expected {0}, got {1}")]
struct InvalidResultNumberError(usize, usize);
pub trait NumResults<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_results() != N {
return verify_error!(InvalidResultNumberError(N, self.num_results())).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of operands: expected {0}, got {1}")]
struct InvalidOperandNumberError(usize, usize);
pub trait NumOperands<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_operands() != N {
return verify_error!(InvalidOperandNumberError(N, self.num_operands())).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of regions: expected {0}, got {1}")]
struct InvalidRegionNumberError(usize, usize);
pub trait NumRegions<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_regions() != N {
return verify_error!(InvalidRegionNumberError(N, self.num_regions())).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of successors: expected {0}, got {1}")]
struct InvalidSuccessorNumberError(usize, usize);
pub trait NumSuccessors<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_successors() != N {
return verify_error!(InvalidSuccessorNumberError(N, self.num_successors())).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of results: expected at least {0}, got {1}")]
struct InvalidAtLeastResultNumberError(usize, usize);
pub trait AtLeastNumResults<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_results() < N {
return verify_error!(InvalidAtLeastResultNumberError(N, self.num_results())).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of operands: expected at least {0}, got {1}")]
struct InvalidAtLeastOperandNumberError(usize, usize);
pub trait AtLeastNumOperands<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_operands() < N {
return verify_error!(InvalidAtLeastOperandNumberError(N, self.num_operands())).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of regions: expected at least {0}, got {1}")]
struct InvalidAtLeastRegionNumberError(usize, usize);
pub trait AtLeastNumRegions<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_regions() < N {
return verify_error!(InvalidAtLeastRegionNumberError(N, self.num_regions())).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid number of successors: expected at least {0}, got {1}")]
struct InvalidAtLeastSuccessorNumberError(usize, usize);
pub trait AtLeastNumSuccessors<const N: usize>: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_successors() < N {
return verify_error!(InvalidAtLeastSuccessorNumberError(N, self.num_successors()))
.into();
}
Ok(())
}
}
pub trait VariadicOperands: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> { Ok(()) }
}
pub trait VariadicResults: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> { Ok(()) }
}
pub trait VariadicRegions: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> { Ok(()) }
}
pub trait VariadicSuccessors: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> { Ok(()) }
}
pub trait FloatLikeTy: Ty {
fn verify(&self, _ctx: &Context) -> VerifyResult<()> { Ok(()) }
}
pub trait IntegerLikeTy: Ty {
fn verify(&self, _ctx: &Context) -> VerifyResult<()> { Ok(()) }
}
#[derive(Debug, Error)]
#[error("operand is not float-like")]
struct NotFloatLikeError;
pub trait FloatLikeOperands: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
for ty in self.operand_tys(ctx) {
if !ty.deref(&ctx.tys).impls::<dyn FloatLikeTy>(ctx) {
return verify_error!(NotFloatLikeError).into();
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("operand is not integer-like")]
struct NotIntegerLikeError;
pub trait IntegerLikeOperands: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
for ty in self.operand_tys(ctx) {
if !ty.deref(&ctx.tys).impls::<dyn IntegerLikeTy>(ctx) {
return verify_error!(NotIntegerLikeError).into();
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("result is not float-like")]
struct NotFloatLikeResultError;
pub trait FloatLikeResults: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
for ty in self.result_tys(ctx) {
if !ty.deref(&ctx.tys).impls::<dyn FloatLikeTy>(ctx) {
return verify_error!(NotFloatLikeResultError).into();
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("result is not integer-like")]
struct NotIntegerLikeResultError;
pub trait IntegerLikeResults: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
for ty in self.result_tys(ctx) {
if !ty.deref(&ctx.tys).impls::<dyn IntegerLikeTy>(ctx) {
return verify_error!(NotIntegerLikeResultError).into();
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("operands have different types")]
struct DifferentOperandTypesError;
pub trait SameOperandTys: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
let operand_tys = self.operand_tys(ctx);
if operand_tys.is_empty() {
return Ok(());
}
let operand_ty = operand_tys[0];
for ty in operand_tys {
if ty != operand_ty {
return verify_error!(DifferentOperandTypesError).into();
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("results have different types")]
struct DifferentResultTysError;
pub trait SameResultTys: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
let result_tys = self.result_tys(ctx);
if result_tys.is_empty() {
return Ok(());
}
let result_ty = result_tys[0];
for ty in result_tys {
if ty != result_ty {
return verify_error!(DifferentResultTysError).into();
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("results and operands have different types")]
struct DifferentOperandAndResultTysError;
pub trait SameOperandAndResultTys: SameOperandTys + SameResultTys {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
<Self as SameOperandTys>::verify(self, ctx)?;
<Self as SameResultTys>::verify(self, ctx)?;
let operand_tys = self.operand_tys(ctx);
let result_tys = self.result_tys(ctx);
if operand_tys.is_empty() {
return Ok(());
}
let operand_ty = operand_tys[0];
if result_tys.is_empty() {
return Ok(());
}
let result_ty = result_tys[0];
if operand_ty != result_ty {
return verify_error!(DifferentOperandAndResultTysError).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("results and operands have different numbers")]
struct DifferentOperandAndResultNumberError;
pub trait SameOperandsAndResultsNum: Op {
fn verify(&self, _: &Context) -> VerifyResult<()> {
if self.num_operands() != self.num_results() {
return verify_error!(DifferentOperandAndResultNumberError).into();
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid operand type, expected {0}")]
pub struct InvalidOperandTyError(String);
pub trait OperandTysAre<T: Ty>: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
for ty in self.operand_tys(ctx) {
if !ty.deref(&ctx.tys).is_a::<T>() {
return verify_error!(InvalidOperandTyError(T::mnemonic_static().to_string()))
.into();
}
}
Ok(())
}
}
#[derive(Debug, Error)]
#[error("invalid result type, expected {0}")]
pub struct InvalidResultTyError(String);
pub trait ResultTysAre<T: Ty>: Op {
fn verify(&self, ctx: &Context) -> VerifyResult<()> {
for ty in self.result_tys(ctx) {
if !ty.deref(&ctx.tys).is_a::<T>() {
return verify_error!(InvalidResultTyError(T::mnemonic_static().to_string()))
.into();
}
}
Ok(())
}
}