3 traits::{Bool, Compare, Context, ConvertTo, Float, Int, Make, SInt, Select, UInt},
9 fmt::{self, Write as _},
12 Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
13 DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
19 use typed_arena::Arena;
21 macro_rules! make_enum {
23 $vis:vis enum $enum:ident {
30 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39 $vis const fn as_str(self) -> &'static str {
42 Self::$name => stringify!($name),
48 impl fmt::Display for $enum {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.write_str(self.as_str())
73 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
74 pub struct VectorType {
75 pub element: ScalarType,
78 impl fmt::Display for VectorType {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "vec<{}>", self.element)
84 impl From<ScalarType> for Type {
85 fn from(v: ScalarType) -> Self {
90 impl From<VectorType> for Type {
91 fn from(v: VectorType) -> Self {
96 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
102 impl fmt::Display for Type {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 Type::Scalar(v) => v.fmt(f),
106 Type::Vector(v) => v.fmt(f),
111 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
112 pub enum ScalarConstant {
127 macro_rules! make_scalar_constant_get {
128 ($ty:ident, $enumerant:ident) => {
129 pub fn $ty(self) -> Option<$ty> {
130 if let Self::$enumerant(v) = self {
139 macro_rules! make_scalar_constant_from {
140 ($ty:ident, $enumerant:ident) => {
141 impl From<$ty> for ScalarConstant {
142 fn from(v: $ty) -> Self {
146 impl From<$ty> for Constant {
147 fn from(v: $ty) -> Self {
148 Self::Scalar(v.into())
151 impl From<$ty> for Value<'_> {
152 fn from(v: $ty) -> Self {
153 Self::Constant(v.into())
159 make_scalar_constant_from!(bool, Bool);
160 make_scalar_constant_from!(u8, U8);
161 make_scalar_constant_from!(u16, U16);
162 make_scalar_constant_from!(u32, U32);
163 make_scalar_constant_from!(u64, U64);
164 make_scalar_constant_from!(i8, I8);
165 make_scalar_constant_from!(i16, I16);
166 make_scalar_constant_from!(i32, I32);
167 make_scalar_constant_from!(i64, I64);
169 impl ScalarConstant {
170 pub const fn ty(self) -> ScalarType {
172 ScalarConstant::Bool(_) => ScalarType::Bool,
173 ScalarConstant::U8(_) => ScalarType::U8,
174 ScalarConstant::U16(_) => ScalarType::U16,
175 ScalarConstant::U32(_) => ScalarType::U32,
176 ScalarConstant::U64(_) => ScalarType::U64,
177 ScalarConstant::I8(_) => ScalarType::I8,
178 ScalarConstant::I16(_) => ScalarType::I16,
179 ScalarConstant::I32(_) => ScalarType::I32,
180 ScalarConstant::I64(_) => ScalarType::I64,
181 ScalarConstant::F16 { .. } => ScalarType::F16,
182 ScalarConstant::F32 { .. } => ScalarType::F32,
183 ScalarConstant::F64 { .. } => ScalarType::F64,
186 pub const fn from_f16_bits(bits: u16) -> Self {
189 pub const fn from_f32_bits(bits: u32) -> Self {
192 pub const fn from_f64_bits(bits: u64) -> Self {
195 pub const fn f16_bits(self) -> Option<u16> {
196 if let Self::F16 { bits } = self {
202 pub const fn f32_bits(self) -> Option<u32> {
203 if let Self::F32 { bits } = self {
209 pub const fn f64_bits(self) -> Option<u64> {
210 if let Self::F64 { bits } = self {
216 make_scalar_constant_get!(bool, Bool);
217 make_scalar_constant_get!(u8, U8);
218 make_scalar_constant_get!(u16, U16);
219 make_scalar_constant_get!(u32, U32);
220 make_scalar_constant_get!(u64, U64);
221 make_scalar_constant_get!(i8, I8);
222 make_scalar_constant_get!(i16, I16);
223 make_scalar_constant_get!(i32, I32);
224 make_scalar_constant_get!(i64, I64);
227 impl fmt::Display for ScalarConstant {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 ScalarConstant::Bool(false) => write!(f, "false"),
231 ScalarConstant::Bool(true) => write!(f, "true"),
232 ScalarConstant::U8(v) => write!(f, "{:#X}_u8", v),
233 ScalarConstant::U16(v) => write!(f, "{:#X}_u16", v),
234 ScalarConstant::U32(v) => write!(f, "{:#X}_u32", v),
235 ScalarConstant::U64(v) => write!(f, "{:#X}_u64", v),
236 ScalarConstant::I8(v) => write!(f, "{:#X}_i8", v),
237 ScalarConstant::I16(v) => write!(f, "{:#X}_i16", v),
238 ScalarConstant::I32(v) => write!(f, "{:#X}_i32", v),
239 ScalarConstant::I64(v) => write!(f, "{:#X}_i64", v),
240 ScalarConstant::F16 { bits } => write!(f, "{:#X}_f16", bits),
241 ScalarConstant::F32 { bits } => write!(f, "{:#X}_f32", bits),
242 ScalarConstant::F64 { bits } => write!(f, "{:#X}_f64", bits),
247 impl fmt::Debug for ScalarConstant {
248 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249 fmt::Display::fmt(self, f)
253 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
254 pub struct VectorSplatConstant {
255 pub element: ScalarConstant,
258 impl VectorSplatConstant {
259 pub const fn ty(self) -> VectorType {
261 element: self.element.ty(),
266 impl fmt::Display for VectorSplatConstant {
267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268 write!(f, "splat({})", self.element)
272 impl From<ScalarConstant> for Constant {
273 fn from(v: ScalarConstant) -> Self {
278 impl From<VectorSplatConstant> for Constant {
279 fn from(v: VectorSplatConstant) -> Self {
280 Constant::VectorSplat(v)
284 impl From<ScalarConstant> for Value<'_> {
285 fn from(v: ScalarConstant) -> Self {
286 Value::Constant(v.into())
290 impl From<VectorSplatConstant> for Value<'_> {
291 fn from(v: VectorSplatConstant) -> Self {
292 Value::Constant(v.into())
296 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
298 Scalar(ScalarConstant),
299 VectorSplat(VectorSplatConstant),
303 pub const fn ty(self) -> Type {
305 Constant::Scalar(v) => Type::Scalar(v.ty()),
306 Constant::VectorSplat(v) => Type::Vector(v.ty()),
311 impl fmt::Display for Constant {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 Constant::Scalar(v) => v.fmt(f),
315 Constant::VectorSplat(v) => v.fmt(f),
321 pub struct Input<'ctx> {
326 impl fmt::Display for Input<'_> {
327 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328 write!(f, "in<{}>", self.name)
332 #[derive(Copy, Clone)]
333 pub enum Value<'ctx> {
334 Input(&'ctx Input<'ctx>),
336 OpResult(&'ctx Operation<'ctx>),
339 impl<'ctx> Value<'ctx> {
340 pub const fn ty(self) -> Type {
342 Value::Input(v) => v.ty,
343 Value::Constant(v) => v.ty(),
344 Value::OpResult(v) => v.result_type,
349 impl fmt::Debug for Value<'_> {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 Value::Input(v) => v.fmt(f),
353 Value::Constant(v) => v.fmt(f),
354 Value::OpResult(v) => v.result_id.fmt(f),
359 impl fmt::Display for Value<'_> {
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 Value::Input(v) => v.fmt(f),
363 Value::Constant(v) => v.fmt(f),
364 Value::OpResult(v) => v.result_id.fmt(f),
369 impl<'ctx> From<&'ctx Input<'ctx>> for Value<'ctx> {
370 fn from(v: &'ctx Input<'ctx>) -> Self {
375 impl<'ctx> From<&'ctx Operation<'ctx>> for Value<'ctx> {
376 fn from(v: &'ctx Operation<'ctx>) -> Self {
381 impl<'ctx> From<Constant> for Value<'ctx> {
382 fn from(v: Constant) -> Self {
427 pub struct Operation<'ctx> {
429 pub arguments: Vec<Value<'ctx>>,
430 pub result_type: Type,
431 pub result_id: OperationId,
434 impl fmt::Display for Operation<'_> {
435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 self.result_id, self.result_type, self.opcode
441 let mut separator = " ";
442 for i in &self.arguments {
443 write!(f, "{}{}", separator, i)?;
450 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
451 pub struct OperationId(pub u64);
453 impl fmt::Display for OperationId {
454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455 write!(f, "op_{}", self.0)
460 pub struct IrContext<'ctx> {
461 bytes_arena: Arena<u8>,
462 inputs_arena: Arena<Input<'ctx>>,
463 inputs: RefCell<HashMap<&'ctx str, &'ctx Input<'ctx>>>,
464 operations_arena: Arena<Operation<'ctx>>,
465 operations: RefCell<Vec<&'ctx Operation<'ctx>>>,
466 next_operation_result_id: Cell<u64>,
469 impl fmt::Debug for IrContext<'_> {
470 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471 f.write_str("IrContext { .. }")
475 impl<'ctx> IrContext<'ctx> {
476 pub fn new() -> Self {
479 pub fn make_input<N: Borrow<str> + Into<String>, T: Into<Type>>(
483 ) -> &'ctx Input<'ctx> {
484 let mut inputs = self.inputs.borrow_mut();
485 let name_str = name.borrow();
487 if !name_str.is_empty() && !inputs.contains_key(name_str) {
488 let name = self.bytes_arena.alloc_str(name_str);
489 let input = self.inputs_arena.alloc(Input { name, ty });
490 inputs.insert(name, input);
493 let mut name: String = name.into();
497 let name_len = name.len();
498 let mut tag = 2usize;
500 name.truncate(name_len);
501 write!(name, "_{}", tag).unwrap();
502 if !inputs.contains_key(&*name) {
503 let name = self.bytes_arena.alloc_str(&name);
504 let input = self.inputs_arena.alloc(Input { name, ty });
505 inputs.insert(name, input);
511 pub fn make_operation<A: Into<Vec<Value<'ctx>>>, T: Into<Type>>(
516 ) -> &'ctx Operation<'ctx> {
517 let arguments = arguments.into();
518 let result_type = result_type.into();
519 let result_id = OperationId(self.next_operation_result_id.get());
520 self.next_operation_result_id.set(result_id.0 + 1);
521 let operation = self.operations_arena.alloc(Operation {
527 self.operations.borrow_mut().push(operation);
530 pub fn replace_operations(
532 new_operations: Vec<&'ctx Operation<'ctx>>,
533 ) -> Vec<&'ctx Operation<'ctx>> {
534 self.operations.replace(new_operations)
539 pub struct IrFunction<'ctx> {
540 pub inputs: Vec<&'ctx Input<'ctx>>,
541 pub operations: Vec<&'ctx Operation<'ctx>>,
542 pub outputs: Vec<Value<'ctx>>,
545 impl fmt::Display for IrFunction<'_> {
546 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
547 write!(f, "function(")?;
548 let mut first = true;
549 for input in &self.inputs {
555 write!(f, "{}: {}", input, input.ty)?;
557 match self.outputs.len() {
558 0 => writeln!(f, ") {{")?,
559 1 => writeln!(f, ") -> {} {{", self.outputs[0].ty())?,
561 write!(f, ") -> ({}", self.outputs[0].ty())?;
562 for output in self.outputs.iter().skip(1) {
563 write!(f, ", {}", output.ty())?;
565 writeln!(f, ") {{")?;
568 for operation in &self.operations {
569 writeln!(f, " {}", operation)?;
571 match self.outputs.len() {
572 0 => writeln!(f, "}}")?,
573 1 => writeln!(f, " Return {}\n}}", self.outputs[0])?,
575 write!(f, " Return {}", self.outputs[0])?;
576 for output in self.outputs.iter().skip(1) {
577 write!(f, ", {}", output)?;
579 writeln!(f, "\n}}")?;
586 impl<'ctx> IrFunction<'ctx> {
587 pub fn make<F: IrFunctionMaker<'ctx>>(ctx: &'ctx IrContext<'ctx>, f: F) -> Self {
588 let old_operations = ctx.replace_operations(Vec::new());
589 let (v, inputs) = F::make_inputs(ctx);
590 let outputs = f.call(ctx, v).outputs_to_vec();
591 let operations = ctx.replace_operations(old_operations);
600 pub trait IrFunctionMaker<'ctx>: Sized {
602 type Outputs: IrFunctionMakerOutputs<'ctx>;
603 fn call(self, ctx: &'ctx IrContext<'ctx>, inputs: Self::Inputs) -> Self::Outputs;
604 fn make_inputs(ctx: &'ctx IrContext<'ctx>) -> (Self::Inputs, Vec<&'ctx Input<'ctx>>);
607 pub trait IrFunctionMakerOutputs<'ctx> {
608 fn outputs_to_vec(self) -> Vec<Value<'ctx>>;
611 impl<'ctx, T: IrValue<'ctx>> IrFunctionMakerOutputs<'ctx> for T {
612 fn outputs_to_vec(self) -> Vec<Value<'ctx>> {
613 [self.value()].into()
617 impl<'ctx> IrFunctionMakerOutputs<'ctx> for () {
618 fn outputs_to_vec(self) -> Vec<Value<'ctx>> {
623 impl<'ctx, R: IrFunctionMakerOutputs<'ctx>> IrFunctionMaker<'ctx>
624 for fn(&'ctx IrContext<'ctx>) -> R
628 fn call(self, ctx: &'ctx IrContext<'ctx>, _inputs: Self::Inputs) -> Self::Outputs {
631 fn make_inputs(_ctx: &'ctx IrContext<'ctx>) -> (Self::Inputs, Vec<&'ctx Input<'ctx>>) {
636 macro_rules! impl_ir_function_maker_io {
638 ($first_arg:ident: $first_arg_ty:ident, $($arg:ident: $arg_ty:ident,)*) => {
639 impl<'ctx, $first_arg_ty, $($arg_ty,)* R> IrFunctionMaker<'ctx> for fn(&'ctx IrContext<'ctx>, $first_arg_ty $(, $arg_ty)*) -> R
641 $first_arg_ty: IrValue<'ctx>,
642 $($arg_ty: IrValue<'ctx>,)*
643 R: IrFunctionMakerOutputs<'ctx>,
645 type Inputs = ($first_arg_ty, $($arg_ty,)*);
647 fn call(self, ctx: &'ctx IrContext<'ctx>, inputs: Self::Inputs) -> Self::Outputs {
648 let ($first_arg, $($arg,)*) = inputs;
649 self(ctx, $first_arg$(, $arg)*)
651 fn make_inputs(ctx: &'ctx IrContext<'ctx>) -> (Self::Inputs, Vec<&'ctx Input<'ctx>>) {
652 let mut $first_arg = String::new();
653 $(let mut $arg = String::new();)*
654 for (index, arg) in [&mut $first_arg $(, &mut $arg)*].iter_mut().enumerate() {
655 **arg = format!("arg_{}", index);
657 let $first_arg = $first_arg_ty::make_input(ctx, $first_arg);
658 $(let $arg = $arg_ty::make_input(ctx, $arg);)*
659 (($first_arg.0, $($arg.0,)*), [$first_arg.1 $(, $arg.1)*].into())
662 impl<'ctx, $first_arg_ty, $($arg_ty),*> IrFunctionMakerOutputs<'ctx> for ($first_arg_ty, $($arg_ty,)*)
664 $first_arg_ty: IrValue<'ctx>,
665 $($arg_ty: IrValue<'ctx>,)*
667 fn outputs_to_vec(self) -> Vec<Value<'ctx>> {
668 let ($first_arg, $($arg,)*) = self;
669 [$first_arg.value() $(, $arg.value())*].into()
672 impl_ir_function_maker_io!($($arg: $arg_ty,)*);
676 impl_ir_function_maker_io!(
691 pub trait IrValue<'ctx>: Copy + Make<Context = &'ctx IrContext<'ctx>> {
693 fn new(ctx: &'ctx IrContext<'ctx>, value: Value<'ctx>) -> Self;
694 fn make_input<N: Borrow<str> + Into<String>>(
695 ctx: &'ctx IrContext<'ctx>,
697 ) -> (Self, &'ctx Input<'ctx>) {
698 let input = ctx.make_input(name, Self::TYPE);
699 (Self::new(ctx, input.into()), input)
701 fn value(self) -> Value<'ctx>;
704 macro_rules! ir_value {
705 ($name:ident, $vec_name:ident, TYPE = $scalar_type:ident, fn make($make_var:ident: $prim:ident) {$make:expr}) => {
706 #[derive(Clone, Copy, Debug)]
707 pub struct $name<'ctx> {
708 pub value: Value<'ctx>,
709 pub ctx: &'ctx IrContext<'ctx>,
712 impl<'ctx> IrValue<'ctx> for $name<'ctx> {
713 const TYPE: Type = Type::Scalar(Self::SCALAR_TYPE);
714 fn new(ctx: &'ctx IrContext<'ctx>, value: Value<'ctx>) -> Self {
715 assert_eq!(value.ty(), Self::TYPE);
718 fn value(self) -> Value<'ctx> {
723 impl<'ctx> $name<'ctx> {
724 pub const SCALAR_TYPE: ScalarType = ScalarType::$scalar_type;
727 impl<'ctx> Make for $name<'ctx> {
729 type Context = &'ctx IrContext<'ctx>;
730 fn ctx(self) -> Self::Context {
733 fn make(ctx: Self::Context, $make_var: Self::Prim) -> Self {
734 let value: ScalarConstant = $make;
735 let value = value.into();
740 #[derive(Clone, Copy, Debug)]
741 pub struct $vec_name<'ctx> {
742 pub value: Value<'ctx>,
743 pub ctx: &'ctx IrContext<'ctx>,
746 impl<'ctx> IrValue<'ctx> for $vec_name<'ctx> {
747 const TYPE: Type = Type::Vector(Self::VECTOR_TYPE);
748 fn new(ctx: &'ctx IrContext<'ctx>, value: Value<'ctx>) -> Self {
749 assert_eq!(value.ty(), Self::TYPE);
752 fn value(self) -> Value<'ctx> {
757 impl<'ctx> $vec_name<'ctx> {
758 pub const VECTOR_TYPE: VectorType = VectorType {
759 element: ScalarType::$scalar_type,
763 impl<'ctx> Make for $vec_name<'ctx> {
765 type Context = &'ctx IrContext<'ctx>;
766 fn ctx(self) -> Self::Context {
769 fn make(ctx: Self::Context, $make_var: Self::Prim) -> Self {
772 value: VectorSplatConstant { element }.into(),
778 impl<'ctx> Select<$name<'ctx>> for IrBool<'ctx> {
779 fn select(self, true_v: $name<'ctx>, false_v: $name<'ctx>) -> $name<'ctx> {
784 [self.value, true_v.value, false_v.value],
795 impl<'ctx> Select<$vec_name<'ctx>> for IrVecBool<'ctx> {
796 fn select(self, true_v: $vec_name<'ctx>, false_v: $vec_name<'ctx>) -> $vec_name<'ctx> {
801 [self.value, true_v.value, false_v.value],
812 impl<'ctx> Select<$vec_name<'ctx>> for IrBool<'ctx> {
813 fn select(self, true_v: $vec_name<'ctx>, false_v: $vec_name<'ctx>) -> $vec_name<'ctx> {
818 [self.value, true_v.value, false_v.value],
829 impl<'ctx> From<$name<'ctx>> for $vec_name<'ctx> {
830 fn from(v: $name<'ctx>) -> Self {
833 .make_operation(Opcode::Splat, [v.value], $vec_name::TYPE)
835 Self { value, ctx: v.ctx }
841 macro_rules! impl_bit_ops {
843 impl<'ctx> BitAnd for $ty<'ctx> {
846 fn bitand(self, rhs: Self) -> Self::Output {
849 .make_operation(Opcode::And, [self.value, rhs.value], Self::TYPE)
857 impl<'ctx> BitOr for $ty<'ctx> {
860 fn bitor(self, rhs: Self) -> Self::Output {
863 .make_operation(Opcode::Or, [self.value, rhs.value], Self::TYPE)
871 impl<'ctx> BitXor for $ty<'ctx> {
874 fn bitxor(self, rhs: Self) -> Self::Output {
877 .make_operation(Opcode::Xor, [self.value, rhs.value], Self::TYPE)
885 impl<'ctx> Not for $ty<'ctx> {
888 fn not(self) -> Self::Output {
891 .make_operation(Opcode::Not, [self.value], Self::TYPE)
899 impl<'ctx> BitAndAssign for $ty<'ctx> {
900 fn bitand_assign(&mut self, rhs: Self) {
904 impl<'ctx> BitOrAssign for $ty<'ctx> {
905 fn bitor_assign(&mut self, rhs: Self) {
909 impl<'ctx> BitXorAssign for $ty<'ctx> {
910 fn bitxor_assign(&mut self, rhs: Self) {
917 macro_rules! impl_number_ops {
918 ($ty:ident, $bool:ident) => {
919 impl<'ctx> Add for $ty<'ctx> {
922 fn add(self, rhs: Self) -> Self::Output {
925 .make_operation(Opcode::Add, [self.value, rhs.value], Self::TYPE)
933 impl<'ctx> Sub for $ty<'ctx> {
936 fn sub(self, rhs: Self) -> Self::Output {
939 .make_operation(Opcode::Sub, [self.value, rhs.value], Self::TYPE)
947 impl<'ctx> Mul for $ty<'ctx> {
950 fn mul(self, rhs: Self) -> Self::Output {
953 .make_operation(Opcode::Mul, [self.value, rhs.value], Self::TYPE)
961 impl<'ctx> Div for $ty<'ctx> {
964 fn div(self, rhs: Self) -> Self::Output {
967 .make_operation(Opcode::Div, [self.value, rhs.value], Self::TYPE)
975 impl<'ctx> Rem for $ty<'ctx> {
978 fn rem(self, rhs: Self) -> Self::Output {
981 .make_operation(Opcode::Rem, [self.value, rhs.value], Self::TYPE)
989 impl<'ctx> AddAssign for $ty<'ctx> {
990 fn add_assign(&mut self, rhs: Self) {
994 impl<'ctx> SubAssign for $ty<'ctx> {
995 fn sub_assign(&mut self, rhs: Self) {
999 impl<'ctx> MulAssign for $ty<'ctx> {
1000 fn mul_assign(&mut self, rhs: Self) {
1001 *self = *self * rhs;
1004 impl<'ctx> DivAssign for $ty<'ctx> {
1005 fn div_assign(&mut self, rhs: Self) {
1006 *self = *self / rhs;
1009 impl<'ctx> RemAssign for $ty<'ctx> {
1010 fn rem_assign(&mut self, rhs: Self) {
1011 *self = *self % rhs;
1014 impl<'ctx> Compare for $ty<'ctx> {
1015 type Bool = $bool<'ctx>;
1016 fn eq(self, rhs: Self) -> Self::Bool {
1019 .make_operation(Opcode::CompareEq, [self.value, rhs.value], $bool::TYPE)
1026 fn ne(self, rhs: Self) -> Self::Bool {
1029 .make_operation(Opcode::CompareNe, [self.value, rhs.value], $bool::TYPE)
1036 fn lt(self, rhs: Self) -> Self::Bool {
1039 .make_operation(Opcode::CompareLt, [self.value, rhs.value], $bool::TYPE)
1046 fn gt(self, rhs: Self) -> Self::Bool {
1049 .make_operation(Opcode::CompareGt, [self.value, rhs.value], $bool::TYPE)
1056 fn le(self, rhs: Self) -> Self::Bool {
1059 .make_operation(Opcode::CompareLe, [self.value, rhs.value], $bool::TYPE)
1066 fn ge(self, rhs: Self) -> Self::Bool {
1069 .make_operation(Opcode::CompareGe, [self.value, rhs.value], $bool::TYPE)
1080 macro_rules! impl_bool_compare {
1082 impl<'ctx> Compare for $ty<'ctx> {
1084 fn eq(self, rhs: Self) -> Self::Bool {
1087 fn ne(self, rhs: Self) -> Self::Bool {
1090 fn lt(self, rhs: Self) -> Self::Bool {
1093 fn gt(self, rhs: Self) -> Self::Bool {
1096 fn le(self, rhs: Self) -> Self::Bool {
1099 fn ge(self, rhs: Self) -> Self::Bool {
1106 impl_bool_compare!(IrBool);
1107 impl_bool_compare!(IrVecBool);
1109 macro_rules! impl_shift_ops {
1111 impl<'ctx> Shl for $ty<'ctx> {
1114 fn shl(self, rhs: Self) -> Self::Output {
1117 .make_operation(Opcode::Shl, [self.value, rhs.value], Self::TYPE)
1125 impl<'ctx> Shr for $ty<'ctx> {
1128 fn shr(self, rhs: Self) -> Self::Output {
1131 .make_operation(Opcode::Shr, [self.value, rhs.value], Self::TYPE)
1139 impl<'ctx> ShlAssign for $ty<'ctx> {
1140 fn shl_assign(&mut self, rhs: Self) {
1141 *self = *self << rhs;
1144 impl<'ctx> ShrAssign for $ty<'ctx> {
1145 fn shr_assign(&mut self, rhs: Self) {
1146 *self = *self >> rhs;
1152 macro_rules! impl_neg {
1154 impl<'ctx> Neg for $ty<'ctx> {
1157 fn neg(self) -> Self::Output {
1160 .make_operation(Opcode::Neg, [self.value], Self::TYPE)
1171 macro_rules! impl_int_trait {
1173 impl<'ctx> Int for $ty<'ctx> {
1174 fn leading_zeros(self) -> Self {
1177 .make_operation(Opcode::CountLeadingZeros, [self.value], Self::TYPE)
1184 fn trailing_zeros(self) -> Self {
1187 .make_operation(Opcode::CountTrailingZeros, [self.value], Self::TYPE)
1194 fn count_ones(self) -> Self {
1197 .make_operation(Opcode::CountSetBits, [self.value], Self::TYPE)
1208 macro_rules! impl_integer_ops {
1209 ($scalar:ident, $vec:ident) => {
1210 impl_bit_ops!($scalar);
1211 impl_number_ops!($scalar, IrBool);
1212 impl_shift_ops!($scalar);
1213 impl_bit_ops!($vec);
1214 impl_number_ops!($vec, IrVecBool);
1215 impl_shift_ops!($vec);
1216 impl_int_trait!($scalar);
1217 impl_int_trait!($vec);
1221 macro_rules! impl_uint_ops {
1222 ($scalar:ident, $vec:ident) => {
1223 impl_integer_ops!($scalar, $vec);
1225 impl<'ctx> UInt for $scalar<'ctx> {}
1226 impl<'ctx> UInt for $vec<'ctx> {}
1230 impl_uint_ops!(IrU8, IrVecU8);
1231 impl_uint_ops!(IrU16, IrVecU16);
1232 impl_uint_ops!(IrU32, IrVecU32);
1233 impl_uint_ops!(IrU64, IrVecU64);
1235 macro_rules! impl_sint_ops {
1236 ($scalar:ident, $vec:ident) => {
1237 impl_integer_ops!($scalar, $vec);
1241 impl<'ctx> SInt for $scalar<'ctx> {}
1242 impl<'ctx> SInt for $vec<'ctx> {}
1246 impl_sint_ops!(IrI8, IrVecI8);
1247 impl_sint_ops!(IrI16, IrVecI16);
1248 impl_sint_ops!(IrI32, IrVecI32);
1249 impl_sint_ops!(IrI64, IrVecI64);
1251 macro_rules! impl_float {
1252 ($float:ident, $bits:ident, $signed_bits:ident) => {
1253 impl<'ctx> Float for $float<'ctx> {
1254 type FloatEncoding = <$float<'ctx> as Make>::Prim;
1255 type BitsType = $bits<'ctx>;
1256 type SignedBitsType = $signed_bits<'ctx>;
1257 fn abs(self) -> Self {
1260 .make_operation(Opcode::Abs, [self.value], Self::TYPE)
1267 fn trunc(self) -> Self {
1270 .make_operation(Opcode::Trunc, [self.value], Self::TYPE)
1277 fn ceil(self) -> Self {
1280 .make_operation(Opcode::Ceil, [self.value], Self::TYPE)
1287 fn floor(self) -> Self {
1290 .make_operation(Opcode::Floor, [self.value], Self::TYPE)
1297 fn round(self) -> Self {
1300 .make_operation(Opcode::Round, [self.value], Self::TYPE)
1307 #[cfg(feature = "fma")]
1308 fn fma(self, a: Self, b: Self) -> Self {
1311 .make_operation(Opcode::Fma, [self.value, a.value, b.value], Self::TYPE)
1318 fn is_nan(self) -> Self::Bool {
1323 [self.value, self.value],
1332 fn is_infinite(self) -> Self::Bool {
1335 .make_operation(Opcode::IsInfinite, [self.value], Self::Bool::TYPE)
1342 fn is_finite(self) -> Self::Bool {
1345 .make_operation(Opcode::IsFinite, [self.value], Self::Bool::TYPE)
1352 fn from_bits(v: Self::BitsType) -> Self {
1355 .make_operation(Opcode::FromBits, [v.value], Self::TYPE)
1357 Self { value, ctx: v.ctx }
1359 fn to_bits(self) -> Self::BitsType {
1362 .make_operation(Opcode::ToBits, [self.value], Self::BitsType::TYPE)
1373 macro_rules! impl_float_ops {
1374 ($scalar:ident, $scalar_bits:ident, $scalar_signed_bits:ident, $vec:ident, $vec_bits:ident, $vec_signed_bits:ident) => {
1375 impl_number_ops!($scalar, IrBool);
1376 impl_number_ops!($vec, IrVecBool);
1379 impl_float!($scalar, $scalar_bits, $scalar_signed_bits);
1380 impl_float!($vec, $vec_bits, $vec_signed_bits);
1384 impl_float_ops!(IrF16, IrU16, IrI16, IrVecF16, IrVecU16, IrVecI16);
1385 impl_float_ops!(IrF32, IrU32, IrI32, IrVecF32, IrVecU32, IrVecI32);
1386 impl_float_ops!(IrF64, IrU64, IrI64, IrVecF64, IrVecU64, IrVecI64);
1397 impl<'ctx> Bool for IrBool<'ctx> {}
1398 impl<'ctx> Bool for IrVecBool<'ctx> {}
1400 impl_bit_ops!(IrBool);
1401 impl_bit_ops!(IrVecBool);
1472 ScalarConstant::from_f16_bits(v.to_bits())
1480 ScalarConstant::from_f32_bits(v.to_bits())
1488 ScalarConstant::from_f64_bits(v.to_bits())
1492 macro_rules! impl_convert_to {
1493 ($src:ident -> $dest:ident) => {
1494 impl<'ctx> ConvertTo<$dest<'ctx>> for $src<'ctx> {
1495 fn to(self) -> $dest<'ctx> {
1496 let value = if $src::TYPE == $dest::TYPE {
1501 .make_operation(Opcode::Cast, [self.value], $dest::TYPE)
1511 ($first:ident $(, $ty:ident)*) => {
1513 impl_convert_to!($first -> $ty);
1514 impl_convert_to!($ty -> $first);
1516 impl_convert_to![$($ty),*];
1521 impl_convert_to![IrU8, IrI8, IrU16, IrI16, IrF16, IrU32, IrI32, IrU64, IrI64, IrF32, IrF64];
1524 IrVecU8, IrVecI8, IrVecU16, IrVecI16, IrVecF16, IrVecU32, IrVecI32, IrVecU64, IrVecI64,
1528 macro_rules! impl_from {
1529 ($src:ident => [$($dest:ident),*]) => {
1531 impl<'ctx> From<$src<'ctx>> for $dest<'ctx> {
1532 fn from(v: $src<'ctx>) -> Self {
1540 macro_rules! impl_froms {
1554 impl_from!($u8 => [$u16, $i16, $f16, $u32, $i32, $f32, $u64, $i64, $f64]);
1555 impl_from!($u16 => [$u32, $i32, $f32, $u64, $i64, $f64]);
1556 impl_from!($u32 => [$u64, $i64, $f64]);
1557 impl_from!($i8 => [$i16, $f16, $i32, $f32, $i64, $f64]);
1558 impl_from!($i16 => [$i32, $f32, $i64, $f64]);
1559 impl_from!($i32 => [$i64, $f64]);
1560 impl_from!($f16 => [$f32, $f64]);
1561 impl_from!($f32 => [$f64]);
1593 impl<'ctx> Context for &'ctx IrContext<'ctx> {
1594 type Bool = IrBool<'ctx>;
1595 type U8 = IrU8<'ctx>;
1596 type I8 = IrI8<'ctx>;
1597 type U16 = IrU16<'ctx>;
1598 type I16 = IrI16<'ctx>;
1599 type F16 = IrF16<'ctx>;
1600 type U32 = IrU32<'ctx>;
1601 type I32 = IrI32<'ctx>;
1602 type F32 = IrF32<'ctx>;
1603 type U64 = IrU64<'ctx>;
1604 type I64 = IrI64<'ctx>;
1605 type F64 = IrF64<'ctx>;
1606 type VecBool8 = IrVecBool<'ctx>;
1607 type VecU8 = IrVecU8<'ctx>;
1608 type VecI8 = IrVecI8<'ctx>;
1609 type VecBool16 = IrVecBool<'ctx>;
1610 type VecU16 = IrVecU16<'ctx>;
1611 type VecI16 = IrVecI16<'ctx>;
1612 type VecF16 = IrVecF16<'ctx>;
1613 type VecBool32 = IrVecBool<'ctx>;
1614 type VecU32 = IrVecU32<'ctx>;
1615 type VecI32 = IrVecI32<'ctx>;
1616 type VecF32 = IrVecF32<'ctx>;
1617 type VecBool64 = IrVecBool<'ctx>;
1618 type VecU64 = IrVecU64<'ctx>;
1619 type VecI64 = IrVecI64<'ctx>;
1620 type VecF64 = IrVecF64<'ctx>;
1625 use crate::algorithms;
1632 fn f<Ctx: Context>(ctx: Ctx, a: Ctx::VecU8, b: Ctx::VecF32) -> Ctx::VecF64 {
1633 let a: Ctx::VecF32 = a.into();
1634 (a - (a + b - ctx.make(5f32)).floor()).to()
1636 let ctx = IrContext::new();
1637 fn make_it<'ctx>(ctx: &'ctx IrContext<'ctx>) -> IrFunction<'ctx> {
1638 let f: fn(&'ctx IrContext<'ctx>, IrVecU8<'ctx>, IrVecF32<'ctx>) -> IrVecF64<'ctx> = f;
1639 IrFunction::make(ctx, f)
1641 let text = format!("\n{}", make_it(&ctx));
1642 println!("{}", text);
1646 function(in<arg_0>: vec<U8>, in<arg_1>: vec<F32>) -> vec<F64> {
1647 op_0: vec<F32> = Cast in<arg_0>
1648 op_1: vec<F32> = Add op_0, in<arg_1>
1649 op_2: vec<F32> = Sub op_1, splat(0x40A00000_f32)
1650 op_3: vec<F32> = Floor op_2
1651 op_4: vec<F32> = Sub op_0, op_3
1652 op_5: vec<F64> = Cast op_4
1660 fn test_display_ilogb_f32() {
1661 let ctx = IrContext::new();
1662 fn make_it<'ctx>(ctx: &'ctx IrContext<'ctx>) -> IrFunction<'ctx> {
1663 let f: fn(&'ctx IrContext<'ctx>, IrVecF32<'ctx>) -> IrVecI32<'ctx> =
1664 algorithms::ilogb::ilogb_f32;
1665 IrFunction::make(ctx, f)
1667 let text = format!("\n{}", make_it(&ctx));
1668 println!("{}", text);
1672 function(in<arg_0>: vec<F32>) -> vec<I32> {
1673 op_0: vec<Bool> = IsFinite in<arg_0>
1674 op_1: vec<U32> = ToBits in<arg_0>
1675 op_2: vec<U32> = And op_1, splat(0x7F800000_u32)
1676 op_3: vec<U32> = Shr op_2, splat(0x17_u32)
1677 op_4: vec<Bool> = CompareEq op_3, splat(0x0_u32)
1678 op_5: vec<Bool> = CompareNe in<arg_0>, in<arg_0>
1679 op_6: vec<I32> = Splat 0x80000001_i32
1680 op_7: vec<I32> = Splat 0x7FFFFFFF_i32
1681 op_8: vec<I32> = Select op_5, op_6, op_7
1682 op_9: vec<F32> = Mul in<arg_0>, splat(0x4B000000_f32)
1683 op_10: vec<U32> = ToBits op_9
1684 op_11: vec<U32> = And op_10, splat(0x7F800000_u32)
1685 op_12: vec<U32> = Shr op_11, splat(0x17_u32)
1686 op_13: vec<I32> = Cast op_12
1687 op_14: vec<I32> = Sub op_13, splat(0x7F_i32)
1688 op_15: vec<U32> = ToBits in<arg_0>
1689 op_16: vec<U32> = And op_15, splat(0x7F800000_u32)
1690 op_17: vec<U32> = Shr op_16, splat(0x17_u32)
1691 op_18: vec<I32> = Cast op_17
1692 op_19: vec<I32> = Sub op_18, splat(0x7F_i32)
1693 op_20: vec<I32> = Select op_0, op_19, op_8
1694 op_21: vec<Bool> = CompareEq in<arg_0>, splat(0x0_f32)
1695 op_22: vec<I32> = Splat 0x80000000_i32
1696 op_23: vec<I32> = Sub op_14, splat(0x17_i32)
1697 op_24: vec<I32> = Select op_21, op_22, op_23
1698 op_25: vec<I32> = Select op_4, op_24, op_20