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, "{}_u8", v),
233 ScalarConstant::U16(v) => write!(f, "{}_u16", v),
234 ScalarConstant::U32(v) => write!(f, "{}_u32", v),
235 ScalarConstant::U64(v) => write!(f, "{}_u64", v),
236 ScalarConstant::I8(v) => write!(f, "{}_i8", v),
237 ScalarConstant::I16(v) => write!(f, "{}_i16", v),
238 ScalarConstant::I32(v) => write!(f, "{}_i32", v),
239 ScalarConstant::I64(v) => write!(f, "{}_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 {
424 pub struct Operation<'ctx> {
426 pub arguments: Vec<Value<'ctx>>,
427 pub result_type: Type,
428 pub result_id: OperationId,
431 impl fmt::Display for Operation<'_> {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436 self.result_id, self.result_type, self.opcode
438 let mut separator = " ";
439 for i in &self.arguments {
440 write!(f, "{}{}", separator, i)?;
447 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
448 pub struct OperationId(pub u64);
450 impl fmt::Display for OperationId {
451 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452 write!(f, "op_{}", self.0)
457 pub struct IrContext<'ctx> {
458 bytes_arena: Arena<u8>,
459 inputs_arena: Arena<Input<'ctx>>,
460 inputs: RefCell<HashMap<&'ctx str, &'ctx Input<'ctx>>>,
461 operations_arena: Arena<Operation<'ctx>>,
462 operations: RefCell<Vec<&'ctx Operation<'ctx>>>,
463 next_operation_result_id: Cell<u64>,
466 impl fmt::Debug for IrContext<'_> {
467 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
468 f.write_str("IrContext { .. }")
472 impl<'ctx> IrContext<'ctx> {
473 pub fn new() -> Self {
476 pub fn make_input<N: Borrow<str> + Into<String>, T: Into<Type>>(
480 ) -> &'ctx Input<'ctx> {
481 let mut inputs = self.inputs.borrow_mut();
482 let name_str = name.borrow();
484 if !name_str.is_empty() && !inputs.contains_key(name_str) {
485 let name = self.bytes_arena.alloc_str(name_str);
486 let input = self.inputs_arena.alloc(Input { name, ty });
487 inputs.insert(name, input);
490 let mut name: String = name.into();
494 let name_len = name.len();
495 let mut tag = 2usize;
497 name.truncate(name_len);
498 write!(name, "_{}", tag).unwrap();
499 if !inputs.contains_key(&*name) {
500 let name = self.bytes_arena.alloc_str(&name);
501 let input = self.inputs_arena.alloc(Input { name, ty });
502 inputs.insert(name, input);
508 pub fn make_operation<A: Into<Vec<Value<'ctx>>>, T: Into<Type>>(
513 ) -> &'ctx Operation<'ctx> {
514 let arguments = arguments.into();
515 let result_type = result_type.into();
516 let result_id = OperationId(self.next_operation_result_id.get());
517 self.next_operation_result_id.set(result_id.0 + 1);
518 let operation = self.operations_arena.alloc(Operation {
524 self.operations.borrow_mut().push(operation);
527 pub fn replace_operations(
529 new_operations: Vec<&'ctx Operation<'ctx>>,
530 ) -> Vec<&'ctx Operation<'ctx>> {
531 self.operations.replace(new_operations)
536 pub struct IrFunction<'ctx> {
537 pub inputs: Vec<&'ctx Input<'ctx>>,
538 pub operations: Vec<&'ctx Operation<'ctx>>,
539 pub outputs: Vec<Value<'ctx>>,
542 impl fmt::Display for IrFunction<'_> {
543 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
544 write!(f, "function(")?;
545 let mut first = true;
546 for input in &self.inputs {
552 write!(f, "{}: {}", input, input.ty)?;
554 match self.outputs.len() {
555 0 => writeln!(f, ") {{")?,
556 1 => writeln!(f, ") -> {} {{", self.outputs[0].ty())?,
558 write!(f, ") -> ({}", self.outputs[0].ty())?;
559 for output in self.outputs.iter().skip(1) {
560 write!(f, ", {}", output.ty())?;
562 writeln!(f, ") {{")?;
565 for operation in &self.operations {
566 writeln!(f, " {}", operation)?;
568 match self.outputs.len() {
569 0 => writeln!(f, "}}")?,
570 1 => writeln!(f, " Return {}\n}}", self.outputs[0])?,
572 write!(f, " Return {}", self.outputs[0])?;
573 for output in self.outputs.iter().skip(1) {
574 write!(f, ", {}", output)?;
576 writeln!(f, "\n}}")?;
583 impl<'ctx> IrFunction<'ctx> {
584 pub fn make<F: IrFunctionMaker<'ctx>>(ctx: &'ctx IrContext<'ctx>, f: F) -> Self {
585 let old_operations = ctx.replace_operations(Vec::new());
586 let (v, inputs) = F::make_inputs(ctx);
587 let outputs = f.call(ctx, v).outputs_to_vec();
588 let operations = ctx.replace_operations(old_operations);
597 pub trait IrFunctionMaker<'ctx>: Sized {
599 type Outputs: IrFunctionMakerOutputs<'ctx>;
600 fn call(self, ctx: &'ctx IrContext<'ctx>, inputs: Self::Inputs) -> Self::Outputs;
601 fn make_inputs(ctx: &'ctx IrContext<'ctx>) -> (Self::Inputs, Vec<&'ctx Input<'ctx>>);
604 pub trait IrFunctionMakerOutputs<'ctx> {
605 fn outputs_to_vec(self) -> Vec<Value<'ctx>>;
608 impl<'ctx, T: IrValue<'ctx>> IrFunctionMakerOutputs<'ctx> for T {
609 fn outputs_to_vec(self) -> Vec<Value<'ctx>> {
610 [self.value()].into()
614 impl<'ctx> IrFunctionMakerOutputs<'ctx> for () {
615 fn outputs_to_vec(self) -> Vec<Value<'ctx>> {
620 impl<'ctx, R: IrFunctionMakerOutputs<'ctx>> IrFunctionMaker<'ctx>
621 for fn(&'ctx IrContext<'ctx>) -> R
625 fn call(self, ctx: &'ctx IrContext<'ctx>, _inputs: Self::Inputs) -> Self::Outputs {
628 fn make_inputs(_ctx: &'ctx IrContext<'ctx>) -> (Self::Inputs, Vec<&'ctx Input<'ctx>>) {
633 macro_rules! impl_ir_function_maker_io {
635 ($first_arg:ident: $first_arg_ty:ident, $($arg:ident: $arg_ty:ident,)*) => {
636 impl<'ctx, $first_arg_ty, $($arg_ty,)* R> IrFunctionMaker<'ctx> for fn(&'ctx IrContext<'ctx>, $first_arg_ty $(, $arg_ty)*) -> R
638 $first_arg_ty: IrValue<'ctx>,
639 $($arg_ty: IrValue<'ctx>,)*
640 R: IrFunctionMakerOutputs<'ctx>,
642 type Inputs = ($first_arg_ty, $($arg_ty,)*);
644 fn call(self, ctx: &'ctx IrContext<'ctx>, inputs: Self::Inputs) -> Self::Outputs {
645 let ($first_arg, $($arg,)*) = inputs;
646 self(ctx, $first_arg$(, $arg)*)
648 fn make_inputs(ctx: &'ctx IrContext<'ctx>) -> (Self::Inputs, Vec<&'ctx Input<'ctx>>) {
649 let mut $first_arg = String::new();
650 $(let mut $arg = String::new();)*
651 for (index, arg) in [&mut $first_arg $(, &mut $arg)*].iter_mut().enumerate() {
652 **arg = format!("arg_{}", index);
654 let $first_arg = $first_arg_ty::make_input(ctx, $first_arg);
655 $(let $arg = $arg_ty::make_input(ctx, $arg);)*
656 (($first_arg.0, $($arg.0,)*), [$first_arg.1 $(, $arg.1)*].into())
659 impl<'ctx, $first_arg_ty, $($arg_ty),*> IrFunctionMakerOutputs<'ctx> for ($first_arg_ty, $($arg_ty,)*)
661 $first_arg_ty: IrValue<'ctx>,
662 $($arg_ty: IrValue<'ctx>,)*
664 fn outputs_to_vec(self) -> Vec<Value<'ctx>> {
665 let ($first_arg, $($arg,)*) = self;
666 [$first_arg.value() $(, $arg.value())*].into()
669 impl_ir_function_maker_io!($($arg: $arg_ty,)*);
673 impl_ir_function_maker_io!(
688 pub trait IrValue<'ctx>: Copy {
690 fn new(ctx: &'ctx IrContext<'ctx>, value: Value<'ctx>) -> Self;
691 fn make_input<N: Borrow<str> + Into<String>>(
692 ctx: &'ctx IrContext<'ctx>,
694 ) -> (Self, &'ctx Input<'ctx>) {
695 let input = ctx.make_input(name, Self::TYPE);
696 (Self::new(ctx, input.into()), input)
698 fn ctx(self) -> &'ctx IrContext<'ctx>;
699 fn value(self) -> Value<'ctx>;
702 macro_rules! ir_value {
703 ($name:ident, $vec_name:ident, TYPE = $scalar_type:ident, fn make($make_var:ident: $prim:ident) {$make:expr}) => {
704 #[derive(Clone, Copy, Debug)]
705 pub struct $name<'ctx> {
706 pub value: Value<'ctx>,
707 pub ctx: &'ctx IrContext<'ctx>,
710 impl<'ctx> IrValue<'ctx> for $name<'ctx> {
711 const TYPE: Type = Type::Scalar(Self::SCALAR_TYPE);
712 fn new(ctx: &'ctx IrContext<'ctx>, value: Value<'ctx>) -> Self {
713 assert_eq!(value.ty(), Self::TYPE);
716 fn ctx(self) -> &'ctx IrContext<'ctx> {
719 fn value(self) -> Value<'ctx> {
724 impl<'ctx> $name<'ctx> {
725 pub const SCALAR_TYPE: ScalarType = ScalarType::$scalar_type;
728 impl<'ctx> Make<&'ctx IrContext<'ctx>> for $name<'ctx> {
731 fn make(ctx: &'ctx IrContext<'ctx>, $make_var: Self::Prim) -> Self {
732 let value: ScalarConstant = $make;
733 let value = value.into();
738 #[derive(Clone, Copy, Debug)]
739 pub struct $vec_name<'ctx> {
740 pub value: Value<'ctx>,
741 pub ctx: &'ctx IrContext<'ctx>,
744 impl<'ctx> IrValue<'ctx> for $vec_name<'ctx> {
745 const TYPE: Type = Type::Vector(Self::VECTOR_TYPE);
746 fn new(ctx: &'ctx IrContext<'ctx>, value: Value<'ctx>) -> Self {
747 assert_eq!(value.ty(), Self::TYPE);
750 fn ctx(self) -> &'ctx IrContext<'ctx> {
753 fn value(self) -> Value<'ctx> {
758 impl<'ctx> $vec_name<'ctx> {
759 pub const VECTOR_TYPE: VectorType = VectorType {
760 element: ScalarType::$scalar_type,
764 impl<'ctx> Make<&'ctx IrContext<'ctx>> for $vec_name<'ctx> {
767 fn make(ctx: &'ctx IrContext<'ctx>, $make_var: Self::Prim) -> Self {
770 value: VectorSplatConstant { element }.into(),
776 impl<'ctx> Select<$name<'ctx>> for IrBool<'ctx> {
777 fn select(self, true_v: $name<'ctx>, false_v: $name<'ctx>) -> $name<'ctx> {
782 [self.value, true_v.value, false_v.value],
793 impl<'ctx> Select<$vec_name<'ctx>> for IrVecBool<'ctx> {
794 fn select(self, true_v: $vec_name<'ctx>, false_v: $vec_name<'ctx>) -> $vec_name<'ctx> {
799 [self.value, true_v.value, false_v.value],
810 impl<'ctx> From<$name<'ctx>> for $vec_name<'ctx> {
811 fn from(v: $name<'ctx>) -> Self {
814 .make_operation(Opcode::Splat, [v.value], $vec_name::TYPE)
816 Self { value, ctx: v.ctx }
822 macro_rules! impl_bit_ops {
824 impl<'ctx> BitAnd for $ty<'ctx> {
827 fn bitand(self, rhs: Self) -> Self::Output {
830 .make_operation(Opcode::And, [self.value, rhs.value], Self::TYPE)
838 impl<'ctx> BitOr for $ty<'ctx> {
841 fn bitor(self, rhs: Self) -> Self::Output {
844 .make_operation(Opcode::Or, [self.value, rhs.value], Self::TYPE)
852 impl<'ctx> BitXor for $ty<'ctx> {
855 fn bitxor(self, rhs: Self) -> Self::Output {
858 .make_operation(Opcode::Xor, [self.value, rhs.value], Self::TYPE)
866 impl<'ctx> Not for $ty<'ctx> {
869 fn not(self) -> Self::Output {
872 .make_operation(Opcode::Not, [self.value], Self::TYPE)
880 impl<'ctx> BitAndAssign for $ty<'ctx> {
881 fn bitand_assign(&mut self, rhs: Self) {
885 impl<'ctx> BitOrAssign for $ty<'ctx> {
886 fn bitor_assign(&mut self, rhs: Self) {
890 impl<'ctx> BitXorAssign for $ty<'ctx> {
891 fn bitxor_assign(&mut self, rhs: Self) {
898 macro_rules! impl_number_ops {
899 ($ty:ident, $bool:ident) => {
900 impl<'ctx> Add for $ty<'ctx> {
903 fn add(self, rhs: Self) -> Self::Output {
906 .make_operation(Opcode::Add, [self.value, rhs.value], Self::TYPE)
914 impl<'ctx> Sub for $ty<'ctx> {
917 fn sub(self, rhs: Self) -> Self::Output {
920 .make_operation(Opcode::Sub, [self.value, rhs.value], Self::TYPE)
928 impl<'ctx> Mul for $ty<'ctx> {
931 fn mul(self, rhs: Self) -> Self::Output {
934 .make_operation(Opcode::Mul, [self.value, rhs.value], Self::TYPE)
942 impl<'ctx> Div for $ty<'ctx> {
945 fn div(self, rhs: Self) -> Self::Output {
948 .make_operation(Opcode::Div, [self.value, rhs.value], Self::TYPE)
956 impl<'ctx> Rem for $ty<'ctx> {
959 fn rem(self, rhs: Self) -> Self::Output {
962 .make_operation(Opcode::Rem, [self.value, rhs.value], Self::TYPE)
970 impl<'ctx> AddAssign for $ty<'ctx> {
971 fn add_assign(&mut self, rhs: Self) {
975 impl<'ctx> SubAssign for $ty<'ctx> {
976 fn sub_assign(&mut self, rhs: Self) {
980 impl<'ctx> MulAssign for $ty<'ctx> {
981 fn mul_assign(&mut self, rhs: Self) {
985 impl<'ctx> DivAssign for $ty<'ctx> {
986 fn div_assign(&mut self, rhs: Self) {
990 impl<'ctx> RemAssign for $ty<'ctx> {
991 fn rem_assign(&mut self, rhs: Self) {
995 impl<'ctx> Compare for $ty<'ctx> {
996 type Bool = $bool<'ctx>;
997 fn eq(self, rhs: Self) -> Self::Bool {
1000 .make_operation(Opcode::CompareEq, [self.value, rhs.value], $bool::TYPE)
1007 fn ne(self, rhs: Self) -> Self::Bool {
1010 .make_operation(Opcode::CompareNe, [self.value, rhs.value], $bool::TYPE)
1017 fn lt(self, rhs: Self) -> Self::Bool {
1020 .make_operation(Opcode::CompareLt, [self.value, rhs.value], $bool::TYPE)
1027 fn gt(self, rhs: Self) -> Self::Bool {
1030 .make_operation(Opcode::CompareGt, [self.value, rhs.value], $bool::TYPE)
1037 fn le(self, rhs: Self) -> Self::Bool {
1040 .make_operation(Opcode::CompareLe, [self.value, rhs.value], $bool::TYPE)
1047 fn ge(self, rhs: Self) -> Self::Bool {
1050 .make_operation(Opcode::CompareGe, [self.value, rhs.value], $bool::TYPE)
1061 macro_rules! impl_shift_ops {
1062 ($ty:ident, $rhs:ident) => {
1063 impl<'ctx> Shl<$rhs<'ctx>> for $ty<'ctx> {
1066 fn shl(self, rhs: $rhs<'ctx>) -> Self::Output {
1069 .make_operation(Opcode::Shl, [self.value, rhs.value], Self::TYPE)
1077 impl<'ctx> Shr<$rhs<'ctx>> for $ty<'ctx> {
1080 fn shr(self, rhs: $rhs<'ctx>) -> Self::Output {
1083 .make_operation(Opcode::Shr, [self.value, rhs.value], Self::TYPE)
1091 impl<'ctx> ShlAssign<$rhs<'ctx>> for $ty<'ctx> {
1092 fn shl_assign(&mut self, rhs: $rhs<'ctx>) {
1093 *self = *self << rhs;
1096 impl<'ctx> ShrAssign<$rhs<'ctx>> for $ty<'ctx> {
1097 fn shr_assign(&mut self, rhs: $rhs<'ctx>) {
1098 *self = *self >> rhs;
1104 macro_rules! impl_neg {
1106 impl<'ctx> Neg for $ty<'ctx> {
1109 fn neg(self) -> Self::Output {
1112 .make_operation(Opcode::Neg, [self.value], Self::TYPE)
1123 macro_rules! impl_integer_ops {
1124 ($scalar:ident, $vec:ident) => {
1125 impl_bit_ops!($scalar);
1126 impl_number_ops!($scalar, IrBool);
1127 impl_shift_ops!($scalar, IrU32);
1128 impl_bit_ops!($vec);
1129 impl_number_ops!($vec, IrVecBool);
1130 impl_shift_ops!($vec, IrVecU32);
1132 impl<'ctx> Int<IrU32<'ctx>> for $scalar<'ctx> {}
1133 impl<'ctx> Int<IrVecU32<'ctx>> for $vec<'ctx> {}
1137 macro_rules! impl_uint_ops {
1138 ($scalar:ident, $vec:ident) => {
1139 impl_integer_ops!($scalar, $vec);
1141 impl<'ctx> UInt<IrU32<'ctx>> for $scalar<'ctx> {}
1142 impl<'ctx> UInt<IrVecU32<'ctx>> for $vec<'ctx> {}
1146 impl_uint_ops!(IrU8, IrVecU8);
1147 impl_uint_ops!(IrU16, IrVecU16);
1148 impl_uint_ops!(IrU32, IrVecU32);
1149 impl_uint_ops!(IrU64, IrVecU64);
1151 macro_rules! impl_sint_ops {
1152 ($scalar:ident, $vec:ident) => {
1153 impl_integer_ops!($scalar, $vec);
1157 impl<'ctx> SInt<IrU32<'ctx>> for $scalar<'ctx> {}
1158 impl<'ctx> SInt<IrVecU32<'ctx>> for $vec<'ctx> {}
1162 impl_sint_ops!(IrI8, IrVecI8);
1163 impl_sint_ops!(IrI16, IrVecI16);
1164 impl_sint_ops!(IrI32, IrVecI32);
1165 impl_sint_ops!(IrI64, IrVecI64);
1167 macro_rules! impl_float {
1168 ($float:ident, $bits:ident, $u32:ident) => {
1169 impl<'ctx> Float<$u32<'ctx>> for $float<'ctx> {
1170 type BitsType = $bits<'ctx>;
1171 fn abs(self) -> Self {
1174 .make_operation(Opcode::Abs, [self.value], Self::TYPE)
1181 fn trunc(self) -> Self {
1184 .make_operation(Opcode::Trunc, [self.value], Self::TYPE)
1191 fn ceil(self) -> Self {
1194 .make_operation(Opcode::Ceil, [self.value], Self::TYPE)
1201 fn floor(self) -> Self {
1204 .make_operation(Opcode::Floor, [self.value], Self::TYPE)
1211 fn round(self) -> Self {
1214 .make_operation(Opcode::Round, [self.value], Self::TYPE)
1221 #[cfg(feature = "fma")]
1222 fn fma(self, a: Self, b: Self) -> Self {
1225 .make_operation(Opcode::Fma, [self.value, a.value, b.value], Self::TYPE)
1232 fn is_nan(self) -> Self::Bool {
1237 [self.value, self.value],
1246 fn is_infinite(self) -> Self::Bool {
1249 .make_operation(Opcode::IsInfinite, [self.value], Self::Bool::TYPE)
1256 fn is_finite(self) -> Self::Bool {
1259 .make_operation(Opcode::IsFinite, [self.value], Self::Bool::TYPE)
1266 fn from_bits(v: Self::BitsType) -> Self {
1269 .make_operation(Opcode::FromBits, [v.value], Self::TYPE)
1271 Self { value, ctx: v.ctx }
1273 fn to_bits(self) -> Self::BitsType {
1276 .make_operation(Opcode::ToBits, [self.value], Self::BitsType::TYPE)
1287 macro_rules! impl_float_ops {
1288 ($scalar:ident, $scalar_bits:ident, $vec:ident, $vec_bits:ident) => {
1289 impl_number_ops!($scalar, IrBool);
1290 impl_number_ops!($vec, IrVecBool);
1293 impl_float!($scalar, $scalar_bits, IrU32);
1294 impl_float!($vec, $vec_bits, IrVecU32);
1298 impl_float_ops!(IrF16, IrU16, IrVecF16, IrVecU16);
1299 impl_float_ops!(IrF32, IrU32, IrVecF32, IrVecU32);
1300 impl_float_ops!(IrF64, IrU64, IrVecF64, IrVecU64);
1311 impl<'ctx> Bool for IrBool<'ctx> {}
1312 impl<'ctx> Bool for IrVecBool<'ctx> {}
1314 impl_bit_ops!(IrBool);
1315 impl_bit_ops!(IrVecBool);
1386 ScalarConstant::from_f16_bits(v.to_bits())
1394 ScalarConstant::from_f32_bits(v.to_bits())
1402 ScalarConstant::from_f64_bits(v.to_bits())
1406 macro_rules! impl_convert_to {
1407 ($($src:ident -> [$($dest:ident),*];)*) => {
1409 impl<'ctx> ConvertTo<$dest<'ctx>> for $src<'ctx> {
1410 fn to(self) -> $dest<'ctx> {
1411 let value = if $src::TYPE == $dest::TYPE {
1416 .make_operation(Opcode::Cast, [self.value], $dest::TYPE)
1427 ([$($src:ident),*] -> $dest:tt;) => {
1434 ([$($src:ident),*];) => {
1436 [$($src),*] -> [$($src),*];
1442 [IrU8, IrI8, IrU16, IrI16, IrF16, IrU32, IrI32, IrU64, IrI64, IrF32, IrF64];
1446 [IrVecU8, IrVecI8, IrVecU16, IrVecI16, IrVecF16, IrVecU32, IrVecI32, IrVecU64, IrVecI64, IrVecF32, IrVecF64];
1449 macro_rules! impl_from {
1450 ($src:ident => [$($dest:ident),*]) => {
1452 impl<'ctx> From<$src<'ctx>> for $dest<'ctx> {
1453 fn from(v: $src<'ctx>) -> Self {
1461 macro_rules! impl_froms {
1475 impl_from!($u8 => [$u16, $i16, $f16, $u32, $i32, $f32, $u64, $i64, $f64]);
1476 impl_from!($u16 => [$u32, $i32, $f32, $u64, $i64, $f64]);
1477 impl_from!($u32 => [$u64, $i64, $f64]);
1478 impl_from!($i8 => [$i16, $f16, $i32, $f32, $i64, $f64]);
1479 impl_from!($i16 => [$i32, $f32, $i64, $f64]);
1480 impl_from!($i32 => [$i64, $f64]);
1481 impl_from!($f16 => [$f32, $f64]);
1482 impl_from!($f32 => [$f64]);
1514 impl<'ctx> Context for &'ctx IrContext<'ctx> {
1515 type Bool = IrBool<'ctx>;
1516 type U8 = IrU8<'ctx>;
1517 type I8 = IrI8<'ctx>;
1518 type U16 = IrU16<'ctx>;
1519 type I16 = IrI16<'ctx>;
1520 type F16 = IrF16<'ctx>;
1521 type U32 = IrU32<'ctx>;
1522 type I32 = IrI32<'ctx>;
1523 type F32 = IrF32<'ctx>;
1524 type U64 = IrU64<'ctx>;
1525 type I64 = IrI64<'ctx>;
1526 type F64 = IrF64<'ctx>;
1527 type VecBool = IrVecBool<'ctx>;
1528 type VecU8 = IrVecU8<'ctx>;
1529 type VecI8 = IrVecI8<'ctx>;
1530 type VecU16 = IrVecU16<'ctx>;
1531 type VecI16 = IrVecI16<'ctx>;
1532 type VecF16 = IrVecF16<'ctx>;
1533 type VecU32 = IrVecU32<'ctx>;
1534 type VecI32 = IrVecI32<'ctx>;
1535 type VecF32 = IrVecF32<'ctx>;
1536 type VecU64 = IrVecU64<'ctx>;
1537 type VecI64 = IrVecI64<'ctx>;
1538 type VecF64 = IrVecF64<'ctx>;
1548 fn f<Ctx: Context>(ctx: Ctx, a: Ctx::VecU8, b: Ctx::VecF32) -> Ctx::VecF64 {
1549 let a: Ctx::VecF32 = a.into();
1550 (a - (a + b - ctx.make(5f32)).floor()).to()
1552 let ctx = IrContext::new();
1553 fn make_it<'ctx>(ctx: &'ctx IrContext<'ctx>) -> IrFunction<'ctx> {
1554 let f: fn(&'ctx IrContext<'ctx>, IrVecU8<'ctx>, IrVecF32<'ctx>) -> IrVecF64<'ctx> = f;
1555 IrFunction::make(ctx, f)
1557 let text = format!("\n{}", make_it(&ctx));
1558 println!("{}", text);
1562 function(in<arg_0>: vec<U8>, in<arg_1>: vec<F32>) -> vec<F64> {
1563 op_0: vec<F32> = Cast in<arg_0>
1564 op_1: vec<F32> = Add op_0, in<arg_1>
1565 op_2: vec<F32> = Sub op_1, splat(0x40A00000_f32)
1566 op_3: vec<F32> = Floor op_2
1567 op_4: vec<F32> = Sub op_0, op_3
1568 op_5: vec<F64> = Cast op_4