1use pliron::{
7 builtin::{
8 attributes::BoolAttr,
9 op_interfaces::{NOpdsInterface, OneOpdInterface, ResultNOfType, SymbolOpInterface},
10 type_interfaces::FloatTypeInterface,
11 },
12 derive::op_interface,
13 dict_key,
14 r#type::type_cast,
15 utils::const_bound_n::I,
16};
17use thiserror::Error;
18
19use pliron::{
20 builtin::{
21 op_interfaces::{OneResultInterface, SameOperandsAndResultType},
22 types::{IntegerType, Signedness},
23 },
24 context::Context,
25 location::Located,
26 op::{Op, op_cast},
27 operation::Operation,
28 result::Result,
29 r#type::{TypeHandle, Typed},
30 value::Value,
31 verify_err,
32};
33
34use crate::{
35 attributes::{AlignmentAttr, FastmathFlagsAttr},
36 types::VectorType,
37};
38
39use super::{attributes::IntegerOverflowFlagsAttr, types::PointerType};
40
41#[op_interface]
43pub trait BinArithOp: SameOperandsAndResultType + OneResultInterface + NOpdsInterface<2> {
44 fn new(ctx: &mut Context, lhs: Value, rhs: Value) -> Self
46 where
47 Self: Sized,
48 {
49 let op = Operation::new(
50 ctx,
51 Self::get_concrete_op_info(),
52 vec![lhs.get_type(ctx)],
53 vec![lhs, rhs],
54 vec![],
55 0,
56 );
57 Self::from_operation(op)
58 }
59
60 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
61 where
62 Self: Sized,
63 {
64 Ok(())
65 }
66
67 fn lhs(&self, ctx: &Context) -> Value
69 where
70 Self: Sized,
71 {
72 self.get_operand_i(ctx, I::<0>.into())
73 }
74
75 fn rhs(&self, ctx: &Context) -> Value
77 where
78 Self: Sized,
79 {
80 self.get_operand_i(ctx, I::<1>.into())
81 }
82}
83
84#[derive(Error, Debug)]
85#[error("Integer binary arithmetic Op can only have signless integer result/operand type")]
86pub struct IntBinArithOpErr;
87
88#[op_interface]
90pub trait IntBinArithOp: BinArithOp {
91 fn verify(op: &dyn Op, ctx: &Context) -> Result<()>
92 where
93 Self: Sized,
94 {
95 let mut ty = op_cast::<dyn BinArithOp>(op)
96 .expect("Op must impl BinArithOp")
97 .operand_type_i(ctx, I::<0>.into());
98
99 if let Some(vec_ty) = ty.deref(ctx).downcast_ref::<VectorType>() {
100 ty = vec_ty.elem_type();
101 }
102
103 let ty = ty.deref(ctx);
104 let Some(int_ty) = ty.downcast_ref::<IntegerType>() else {
105 return verify_err!(op.loc(ctx), IntBinArithOpErr);
106 };
107
108 if int_ty.signedness() != Signedness::Signless {
109 return verify_err!(op.loc(ctx), IntBinArithOpErr);
110 }
111
112 Ok(())
113 }
114}
115
116dict_key!(
117 ATTR_KEY_INTEGER_OVERFLOW_FLAGS,
119 "llvm_integer_overflow_flags"
120);
121
122#[derive(Error, Debug)]
123#[error("IntegerOverflowFlag missing on Op")]
124pub struct IntBinArithOpWithOverflowFlagErr;
125
126#[op_interface]
128pub trait IntBinArithOpWithOverflowFlag: IntBinArithOp {
129 fn new_with_overflow_flag(
131 ctx: &mut Context,
132 lhs: Value,
133 rhs: Value,
134 flag: IntegerOverflowFlagsAttr,
135 ) -> Self
136 where
137 Self: Sized,
138 {
139 let op = Self::new(ctx, lhs, rhs);
140 op.set_integer_overflow_flag(ctx, flag);
141 op
142 }
143
144 fn integer_overflow_flag(&self, ctx: &Context) -> IntegerOverflowFlagsAttr
146 where
147 Self: Sized,
148 {
149 self.get_operation()
150 .deref(ctx)
151 .attributes
152 .get::<IntegerOverflowFlagsAttr>(&ATTR_KEY_INTEGER_OVERFLOW_FLAGS)
153 .expect("Integer overflow flag missing or is of incorrect type")
154 .clone()
155 }
156
157 fn set_integer_overflow_flag(&self, ctx: &Context, flag: IntegerOverflowFlagsAttr)
159 where
160 Self: Sized,
161 {
162 self.get_operation()
163 .deref_mut(ctx)
164 .attributes
165 .set(ATTR_KEY_INTEGER_OVERFLOW_FLAGS.clone(), flag);
166 }
167
168 fn verify(op: &dyn Op, ctx: &Context) -> Result<()>
169 where
170 Self: Sized,
171 {
172 let op = op.get_operation().deref(ctx);
173 if op
174 .attributes
175 .get::<IntegerOverflowFlagsAttr>(&ATTR_KEY_INTEGER_OVERFLOW_FLAGS)
176 .is_none()
177 {
178 return verify_err!(op.loc(), IntBinArithOpWithOverflowFlagErr);
179 }
180
181 Ok(())
182 }
183}
184
185#[derive(Error, Debug)]
186#[error("Floating point arithmetic Op can only have signless floating point result/operand type")]
187pub struct FloatBinArithOpErr;
188
189#[op_interface]
191pub trait FloatBinArithOp: BinArithOp {
192 fn verify(op: &dyn Op, ctx: &Context) -> Result<()>
193 where
194 Self: Sized,
195 {
196 let mut ty = op_cast::<dyn BinArithOp>(op)
197 .expect("Op must impl BinArithOp")
198 .operand_type_i(ctx, I::<0>.into());
199
200 if let Some(vec_ty) = ty.deref(ctx).downcast_ref::<VectorType>() {
201 ty = vec_ty.elem_type();
202 }
203
204 let ty = ty.deref(ctx);
205 if type_cast::<dyn FloatTypeInterface>(&*ty).is_none() {
206 return verify_err!(op.loc(ctx), FloatBinArithOpErr);
207 }
208 Ok(())
209 }
210}
211
212dict_key!(
213 ATTR_KEY_FAST_MATH_FLAGS,
215 "llvm_fast_math_flags"
216);
217
218#[derive(Error, Debug)]
219#[error("Fastmath flag missing on Op")]
220pub struct FastMathFlagMissingErr;
221
222#[op_interface]
224pub trait FastMathFlags {
225 fn fast_math_flags(&self, ctx: &Context) -> FastmathFlagsAttr
227 where
228 Self: Sized,
229 {
230 *self
231 .get_operation()
232 .deref(ctx)
233 .attributes
234 .get::<FastmathFlagsAttr>(&ATTR_KEY_FAST_MATH_FLAGS)
235 .expect("Fast math flags missing or is of incorrect type")
236 }
237
238 fn set_fast_math_flags(&self, ctx: &Context, flag: FastmathFlagsAttr)
240 where
241 Self: Sized,
242 {
243 self.get_operation()
244 .deref_mut(ctx)
245 .attributes
246 .set(ATTR_KEY_FAST_MATH_FLAGS.clone(), flag);
247 }
248
249 fn verify(op: &dyn Op, ctx: &Context) -> Result<()>
250 where
251 Self: Sized,
252 {
253 let op = op.get_operation().deref(ctx);
254 if op
255 .attributes
256 .get::<FastmathFlagsAttr>(&ATTR_KEY_FAST_MATH_FLAGS)
257 .is_none()
258 {
259 return verify_err!(op.loc(), FastmathFlagMissingErr);
260 }
261
262 Ok(())
263 }
264}
265
266#[op_interface]
268pub trait FloatBinArithOpWithFastMathFlags: FloatBinArithOp + FastMathFlags {
269 fn new_with_fast_math_flags(
271 ctx: &mut Context,
272 lhs: Value,
273 rhs: Value,
274 flag: FastmathFlagsAttr,
275 ) -> Self
276 where
277 Self: Sized,
278 {
279 let op = Self::new(ctx, lhs, rhs);
280 op.set_fast_math_flags(ctx, flag);
281 op
282 }
283
284 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
285 where
286 Self: Sized,
287 {
288 Ok(())
289 }
290}
291
292#[derive(Error, Debug)]
293#[error("Fastmath flag missing on Op")]
294pub struct FastmathFlagMissingErr;
295
296dict_key!(
297 ATTR_KEY_NNEG_FLAG,
299 "llvm_nneg_flag"
300);
301
302#[op_interface]
303pub trait NNegFlag {
304 fn nneg(&self, ctx: &Context) -> bool {
306 self.get_operation()
307 .deref(ctx)
308 .attributes
309 .get::<BoolAttr>(&ATTR_KEY_NNEG_FLAG)
310 .expect("NNEG flag missing or is of incorrect type")
311 .clone()
312 .into()
313 }
314 fn set_nneg(&self, ctx: &Context, flag: bool) {
316 self.get_operation()
317 .deref_mut(ctx)
318 .attributes
319 .set(ATTR_KEY_NNEG_FLAG.clone(), BoolAttr::new(flag));
320 }
321 fn verify(op: &dyn Op, ctx: &Context) -> Result<()>
322 where
323 Self: Sized,
324 {
325 let op = op.get_operation().deref(ctx);
326 if op.attributes.get::<BoolAttr>(&ATTR_KEY_NNEG_FLAG).is_none() {
327 return verify_err!(op.loc(), NNegFlagMissingErr);
328 }
329
330 Ok(())
331 }
332}
333
334#[derive(Error, Debug)]
335#[error("NNEG flag missing on Op")]
336pub struct NNegFlagMissingErr;
337
338#[derive(Error, Debug)]
339#[error("Result must be a pointer type, but is not")]
340pub struct PointerTypeResultVerifyErr;
341
342#[op_interface]
344pub trait PointerTypeResult: OneResultInterface + ResultNOfType<0, PointerType> {
345 fn result_pointee_type(&self, ctx: &Context) -> TypeHandle;
347
348 fn verify(op: &dyn Op, ctx: &Context) -> Result<()>
349 where
350 Self: Sized,
351 {
352 if !op_cast::<dyn OneResultInterface>(op)
353 .expect("An Op here must impl OneResultInterface")
354 .result_type(ctx)
355 .deref(ctx)
356 .is::<PointerType>()
357 {
358 return verify_err!(op.loc(ctx), PointerTypeResultVerifyErr);
359 }
360
361 Ok(())
362 }
363}
364
365#[op_interface]
367pub trait CastOpInterface: OneResultInterface + OneOpdInterface {
368 fn new(ctx: &mut Context, operand: Value, res_type: TypeHandle) -> Self
370 where
371 Self: Sized,
372 {
373 let op = Operation::new(
374 ctx,
375 Self::get_concrete_op_info(),
376 vec![res_type],
377 vec![operand],
378 vec![],
379 0,
380 );
381 Self::from_operation(op)
382 }
383
384 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
385 where
386 Self: Sized,
387 {
388 Ok(())
389 }
390}
391
392#[op_interface]
394pub trait CastOpWithNNegInterface: CastOpInterface + NNegFlag {
395 fn new_with_nneg(ctx: &mut Context, operand: Value, res_type: TypeHandle, nneg: bool) -> Self
397 where
398 Self: Sized,
399 {
400 let op = Self::new(ctx, operand, res_type);
401 op.set_nneg(ctx, nneg);
402 op
403 }
404
405 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
406 where
407 Self: Sized,
408 {
409 Ok(())
410 }
411}
412
413#[op_interface]
415pub trait IsDeclaration {
416 fn is_declaration(&self, ctx: &Context) -> bool
418 where
419 Self: Sized;
420
421 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
422 where
423 Self: Sized,
424 {
425 Ok(())
426 }
427}
428
429dict_key!(
430 ATTR_KEY_LLVM_SYMBOL_NAME,
432 "llvm_symbol_name"
433);
434
435#[op_interface]
438pub trait LlvmSymbolName: SymbolOpInterface {
439 fn llvm_symbol_name(&self, ctx: &Context) -> Option<String> {
441 self.get_operation()
442 .deref(ctx)
443 .attributes
444 .get::<pliron::builtin::attributes::StringAttr>(&ATTR_KEY_LLVM_SYMBOL_NAME)
445 .map(|attr| attr.clone().into())
446 }
447
448 fn set_llvm_symbol_name(&self, ctx: &Context, name: String) {
450 self.get_operation().deref_mut(ctx).attributes.set(
451 ATTR_KEY_LLVM_SYMBOL_NAME.clone(),
452 pliron::builtin::attributes::StringAttr::new(name),
453 );
454 }
455
456 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
457 where
458 Self: Sized,
459 {
460 Ok(())
461 }
462}
463
464dict_key!(
465 ATTR_KEY_LLVM_ALIGNMENT,
467 "llvm_alignment"
468);
469
470#[op_interface]
472pub trait AlignableOpInterface {
473 fn alignment(&self, ctx: &Context) -> Option<u32>
475 where
476 Self: Sized,
477 {
478 self.get_operation()
479 .deref(ctx)
480 .attributes
481 .get::<AlignmentAttr>(&ATTR_KEY_LLVM_ALIGNMENT)
482 .map(|attr| attr.0)
483 }
484
485 fn set_alignment(&self, ctx: &Context, alignment: u32)
487 where
488 Self: Sized,
489 {
490 self.get_operation()
491 .deref_mut(ctx)
492 .attributes
493 .set(ATTR_KEY_LLVM_ALIGNMENT.clone(), AlignmentAttr(alignment));
494 }
495
496 fn verify(_op: &dyn Op, _ctx: &Context) -> Result<()>
497 where
498 Self: Sized,
499 {
500 Ok(())
501 }
502}