llvm_ir/
instruction.rs

1use crate::constant::ConstantRef;
2use crate::debugloc::{DebugLoc, HasDebugLoc};
3use crate::function::{CallingConvention, FunctionAttribute, ParameterAttribute};
4use crate::name::Name;
5use crate::operand::Operand;
6use crate::predicates::*;
7#[cfg(feature = "llvm-14-or-lower")]
8use crate::types::NamedStructDef;
9use crate::types::{Type, TypeRef, Typed, Types};
10use either::Either;
11use std::convert::TryFrom;
12use std::fmt::{self, Debug, Display};
13
14/// Non-terminator instructions.
15#[derive(PartialEq, Clone, Debug, Hash)]
16pub enum Instruction {
17    // Integer binary ops
18    Add(Add),
19    Sub(Sub),
20    Mul(Mul),
21    UDiv(UDiv),
22    SDiv(SDiv),
23    URem(URem),
24    SRem(SRem),
25
26    // Bitwise binary ops
27    And(And),
28    Or(Or),
29    Xor(Xor),
30    Shl(Shl),
31    LShr(LShr),
32    AShr(AShr),
33
34    // Floating-point ops
35    FAdd(FAdd),
36    FSub(FSub),
37    FMul(FMul),
38    FDiv(FDiv),
39    FRem(FRem),
40    FNeg(FNeg),
41
42    // Vector ops
43    ExtractElement(ExtractElement),
44    InsertElement(InsertElement),
45    ShuffleVector(ShuffleVector),
46
47    // Aggregate ops
48    ExtractValue(ExtractValue),
49    InsertValue(InsertValue),
50
51    // Memory-related ops
52    Alloca(Alloca),
53    Load(Load),
54    Store(Store),
55    Fence(Fence),
56    CmpXchg(CmpXchg),
57    AtomicRMW(AtomicRMW),
58    GetElementPtr(GetElementPtr),
59
60    // Conversion ops
61    Trunc(Trunc),
62    ZExt(ZExt),
63    SExt(SExt),
64    FPTrunc(FPTrunc),
65    FPExt(FPExt),
66    FPToUI(FPToUI),
67    FPToSI(FPToSI),
68    UIToFP(UIToFP),
69    SIToFP(SIToFP),
70    PtrToInt(PtrToInt),
71    IntToPtr(IntToPtr),
72    BitCast(BitCast),
73    AddrSpaceCast(AddrSpaceCast),
74
75    // LLVM's "other operations" category
76    ICmp(ICmp),
77    FCmp(FCmp),
78    Phi(Phi),
79    Select(Select),
80    #[cfg(feature = "llvm-10-or-greater")]
81    Freeze(Freeze),
82    Call(Call),
83    VAArg(VAArg),
84    LandingPad(LandingPad),
85    CatchPad(CatchPad),
86    CleanupPad(CleanupPad),
87}
88
89/// The [`Type`](../enum.Type.html) of an `Instruction` (or any subtype of `Instruction`) is its result type.
90impl Typed for Instruction {
91    fn get_type(&self, types: &Types) -> TypeRef {
92        match self {
93            Instruction::Add(i) => types.type_of(i),
94            Instruction::Sub(i) => types.type_of(i),
95            Instruction::Mul(i) => types.type_of(i),
96            Instruction::UDiv(i) => types.type_of(i),
97            Instruction::SDiv(i) => types.type_of(i),
98            Instruction::URem(i) => types.type_of(i),
99            Instruction::SRem(i) => types.type_of(i),
100            Instruction::And(i) => types.type_of(i),
101            Instruction::Or(i) => types.type_of(i),
102            Instruction::Xor(i) => types.type_of(i),
103            Instruction::Shl(i) => types.type_of(i),
104            Instruction::LShr(i) => types.type_of(i),
105            Instruction::AShr(i) => types.type_of(i),
106            Instruction::FAdd(i) => types.type_of(i),
107            Instruction::FSub(i) => types.type_of(i),
108            Instruction::FMul(i) => types.type_of(i),
109            Instruction::FDiv(i) => types.type_of(i),
110            Instruction::FRem(i) => types.type_of(i),
111            Instruction::FNeg(i) => types.type_of(i),
112            Instruction::ExtractElement(i) => types.type_of(i),
113            Instruction::InsertElement(i) => types.type_of(i),
114            Instruction::ShuffleVector(i) => types.type_of(i),
115            Instruction::ExtractValue(i) => types.type_of(i),
116            Instruction::InsertValue(i) => types.type_of(i),
117            Instruction::Alloca(i) => types.type_of(i),
118            Instruction::Load(i) => types.type_of(i),
119            Instruction::Store(i) => types.type_of(i),
120            Instruction::Fence(i) => types.type_of(i),
121            Instruction::CmpXchg(i) => types.type_of(i),
122            Instruction::AtomicRMW(i) => types.type_of(i),
123            Instruction::GetElementPtr(i) => types.type_of(i),
124            Instruction::Trunc(i) => types.type_of(i),
125            Instruction::ZExt(i) => types.type_of(i),
126            Instruction::SExt(i) => types.type_of(i),
127            Instruction::FPTrunc(i) => types.type_of(i),
128            Instruction::FPExt(i) => types.type_of(i),
129            Instruction::FPToUI(i) => types.type_of(i),
130            Instruction::FPToSI(i) => types.type_of(i),
131            Instruction::UIToFP(i) => types.type_of(i),
132            Instruction::SIToFP(i) => types.type_of(i),
133            Instruction::PtrToInt(i) => types.type_of(i),
134            Instruction::IntToPtr(i) => types.type_of(i),
135            Instruction::BitCast(i) => types.type_of(i),
136            Instruction::AddrSpaceCast(i) => types.type_of(i),
137            Instruction::ICmp(i) => types.type_of(i),
138            Instruction::FCmp(i) => types.type_of(i),
139            Instruction::Phi(i) => types.type_of(i),
140            Instruction::Select(i) => types.type_of(i),
141            #[cfg(feature = "llvm-10-or-greater")]
142            Instruction::Freeze(i) => types.type_of(i),
143            Instruction::Call(i) => types.type_of(i),
144            Instruction::VAArg(i) => types.type_of(i),
145            Instruction::LandingPad(i) => types.type_of(i),
146            Instruction::CatchPad(i) => types.type_of(i),
147            Instruction::CleanupPad(i) => types.type_of(i),
148        }
149    }
150}
151
152impl HasDebugLoc for Instruction {
153    fn get_debug_loc(&self) -> &Option<DebugLoc> {
154        match self {
155            Instruction::Add(i) => i.get_debug_loc(),
156            Instruction::Sub(i) => i.get_debug_loc(),
157            Instruction::Mul(i) => i.get_debug_loc(),
158            Instruction::UDiv(i) => i.get_debug_loc(),
159            Instruction::SDiv(i) => i.get_debug_loc(),
160            Instruction::URem(i) => i.get_debug_loc(),
161            Instruction::SRem(i) => i.get_debug_loc(),
162            Instruction::And(i) => i.get_debug_loc(),
163            Instruction::Or(i) => i.get_debug_loc(),
164            Instruction::Xor(i) => i.get_debug_loc(),
165            Instruction::Shl(i) => i.get_debug_loc(),
166            Instruction::LShr(i) => i.get_debug_loc(),
167            Instruction::AShr(i) => i.get_debug_loc(),
168            Instruction::FAdd(i) => i.get_debug_loc(),
169            Instruction::FSub(i) => i.get_debug_loc(),
170            Instruction::FMul(i) => i.get_debug_loc(),
171            Instruction::FDiv(i) => i.get_debug_loc(),
172            Instruction::FRem(i) => i.get_debug_loc(),
173            Instruction::FNeg(i) => i.get_debug_loc(),
174            Instruction::ExtractElement(i) => i.get_debug_loc(),
175            Instruction::InsertElement(i) => i.get_debug_loc(),
176            Instruction::ShuffleVector(i) => i.get_debug_loc(),
177            Instruction::ExtractValue(i) => i.get_debug_loc(),
178            Instruction::InsertValue(i) => i.get_debug_loc(),
179            Instruction::Alloca(i) => i.get_debug_loc(),
180            Instruction::Load(i) => i.get_debug_loc(),
181            Instruction::Store(i) => i.get_debug_loc(),
182            Instruction::Fence(i) => i.get_debug_loc(),
183            Instruction::CmpXchg(i) => i.get_debug_loc(),
184            Instruction::AtomicRMW(i) => i.get_debug_loc(),
185            Instruction::GetElementPtr(i) => i.get_debug_loc(),
186            Instruction::Trunc(i) => i.get_debug_loc(),
187            Instruction::ZExt(i) => i.get_debug_loc(),
188            Instruction::SExt(i) => i.get_debug_loc(),
189            Instruction::FPTrunc(i) => i.get_debug_loc(),
190            Instruction::FPExt(i) => i.get_debug_loc(),
191            Instruction::FPToUI(i) => i.get_debug_loc(),
192            Instruction::FPToSI(i) => i.get_debug_loc(),
193            Instruction::UIToFP(i) => i.get_debug_loc(),
194            Instruction::SIToFP(i) => i.get_debug_loc(),
195            Instruction::PtrToInt(i) => i.get_debug_loc(),
196            Instruction::IntToPtr(i) => i.get_debug_loc(),
197            Instruction::BitCast(i) => i.get_debug_loc(),
198            Instruction::AddrSpaceCast(i) => i.get_debug_loc(),
199            Instruction::ICmp(i) => i.get_debug_loc(),
200            Instruction::FCmp(i) => i.get_debug_loc(),
201            Instruction::Phi(i) => i.get_debug_loc(),
202            Instruction::Select(i) => i.get_debug_loc(),
203            #[cfg(feature = "llvm-10-or-greater")]
204            Instruction::Freeze(i) => i.get_debug_loc(),
205            Instruction::Call(i) => i.get_debug_loc(),
206            Instruction::VAArg(i) => i.get_debug_loc(),
207            Instruction::LandingPad(i) => i.get_debug_loc(),
208            Instruction::CatchPad(i) => i.get_debug_loc(),
209            Instruction::CleanupPad(i) => i.get_debug_loc(),
210        }
211    }
212}
213
214impl Instruction {
215    /// Get the result (destination) of the `Instruction`, or `None` if the
216    /// `Instruction` doesn't have a result (has void type).
217    pub fn try_get_result(&self) -> Option<&Name> {
218        match self {
219            Instruction::Add(i) => Some(&i.dest),
220            Instruction::Sub(i) => Some(&i.dest),
221            Instruction::Mul(i) => Some(&i.dest),
222            Instruction::UDiv(i) => Some(&i.dest),
223            Instruction::SDiv(i) => Some(&i.dest),
224            Instruction::URem(i) => Some(&i.dest),
225            Instruction::SRem(i) => Some(&i.dest),
226            Instruction::And(i) => Some(&i.dest),
227            Instruction::Or(i) => Some(&i.dest),
228            Instruction::Xor(i) => Some(&i.dest),
229            Instruction::Shl(i) => Some(&i.dest),
230            Instruction::LShr(i) => Some(&i.dest),
231            Instruction::AShr(i) => Some(&i.dest),
232            Instruction::FAdd(i) => Some(&i.dest),
233            Instruction::FSub(i) => Some(&i.dest),
234            Instruction::FMul(i) => Some(&i.dest),
235            Instruction::FDiv(i) => Some(&i.dest),
236            Instruction::FRem(i) => Some(&i.dest),
237            Instruction::FNeg(i) => Some(&i.dest),
238            Instruction::ExtractElement(i) => Some(&i.dest),
239            Instruction::InsertElement(i) => Some(&i.dest),
240            Instruction::ShuffleVector(i) => Some(&i.dest),
241            Instruction::ExtractValue(i) => Some(&i.dest),
242            Instruction::InsertValue(i) => Some(&i.dest),
243            Instruction::Alloca(i) => Some(&i.dest),
244            Instruction::Load(i) => Some(&i.dest),
245            Instruction::Store(_) => None,
246            Instruction::Fence(_) => None,
247            Instruction::CmpXchg(i) => Some(&i.dest),
248            Instruction::AtomicRMW(i) => Some(&i.dest),
249            Instruction::GetElementPtr(i) => Some(&i.dest),
250            Instruction::Trunc(i) => Some(&i.dest),
251            Instruction::ZExt(i) => Some(&i.dest),
252            Instruction::SExt(i) => Some(&i.dest),
253            Instruction::FPTrunc(i) => Some(&i.dest),
254            Instruction::FPExt(i) => Some(&i.dest),
255            Instruction::FPToUI(i) => Some(&i.dest),
256            Instruction::FPToSI(i) => Some(&i.dest),
257            Instruction::UIToFP(i) => Some(&i.dest),
258            Instruction::SIToFP(i) => Some(&i.dest),
259            Instruction::PtrToInt(i) => Some(&i.dest),
260            Instruction::IntToPtr(i) => Some(&i.dest),
261            Instruction::BitCast(i) => Some(&i.dest),
262            Instruction::AddrSpaceCast(i) => Some(&i.dest),
263            Instruction::ICmp(i) => Some(&i.dest),
264            Instruction::FCmp(i) => Some(&i.dest),
265            Instruction::Phi(i) => Some(&i.dest),
266            Instruction::Select(i) => Some(&i.dest),
267            #[cfg(feature = "llvm-10-or-greater")]
268            Instruction::Freeze(i) => Some(&i.dest),
269            Instruction::Call(i) => i.dest.as_ref(),
270            Instruction::VAArg(i) => Some(&i.dest),
271            Instruction::LandingPad(i) => Some(&i.dest),
272            Instruction::CatchPad(i) => Some(&i.dest),
273            Instruction::CleanupPad(i) => Some(&i.dest),
274        }
275    }
276
277    /// Whether the `Instruction` is atomic
278    pub fn is_atomic(&self) -> bool {
279        match self {
280            Instruction::Add(_) => false,
281            Instruction::Sub(_) => false,
282            Instruction::Mul(_) => false,
283            Instruction::UDiv(_) => false,
284            Instruction::SDiv(_) => false,
285            Instruction::URem(_) => false,
286            Instruction::SRem(_) => false,
287            Instruction::And(_) => false,
288            Instruction::Or(_) => false,
289            Instruction::Xor(_) => false,
290            Instruction::Shl(_) => false,
291            Instruction::LShr(_) => false,
292            Instruction::AShr(_) => false,
293            Instruction::FAdd(_) => false,
294            Instruction::FSub(_) => false,
295            Instruction::FMul(_) => false,
296            Instruction::FDiv(_) => false,
297            Instruction::FRem(_) => false,
298            Instruction::FNeg(_) => false,
299            Instruction::ExtractElement(_) => false,
300            Instruction::InsertElement(_) => false,
301            Instruction::ShuffleVector(_) => false,
302            Instruction::ExtractValue(_) => false,
303            Instruction::InsertValue(_) => false,
304            Instruction::Alloca(_) => false,
305            Instruction::Load(i) => i.atomicity.is_some(),
306            Instruction::Store(i) => i.atomicity.is_some(),
307            Instruction::Fence(_) => true,
308            Instruction::CmpXchg(_) => true,
309            Instruction::AtomicRMW(_) => true,
310            Instruction::GetElementPtr(_) => false,
311            Instruction::Trunc(_) => false,
312            Instruction::ZExt(_) => false,
313            Instruction::SExt(_) => false,
314            Instruction::FPTrunc(_) => false,
315            Instruction::FPExt(_) => false,
316            Instruction::FPToUI(_) => false,
317            Instruction::FPToSI(_) => false,
318            Instruction::UIToFP(_) => false,
319            Instruction::SIToFP(_) => false,
320            Instruction::PtrToInt(_) => false,
321            Instruction::IntToPtr(_) => false,
322            Instruction::BitCast(_) => false,
323            Instruction::AddrSpaceCast(_) => false,
324            Instruction::ICmp(_) => false,
325            Instruction::FCmp(_) => false,
326            Instruction::Phi(_) => false,
327            Instruction::Select(_) => false,
328            #[cfg(feature = "llvm-10-or-greater")]
329            Instruction::Freeze(_) => false,
330            Instruction::Call(_) => false,
331            Instruction::VAArg(_) => false,
332            Instruction::LandingPad(_) => false,
333            Instruction::CatchPad(_) => false,
334            Instruction::CleanupPad(_) => false,
335        }
336    }
337}
338
339/* --TODO not yet implemented: metadata
340pub trait HasMetadata {
341    fn get_metadata(&self) -> &InstructionMetadata;
342}
343
344impl HasMetadata for Instruction {
345    fn get_metadata(&self) -> &InstructionMetadata {
346        match self {
347            Instruction::Add(i) => &i.metadata,
348            Instruction::Sub(i) => &i.metadata,
349            Instruction::Mul(i) => &i.metadata,
350            Instruction::UDiv(i) => &i.metadata,
351            Instruction::SDiv(i) => &i.metadata,
352            Instruction::URem(i) => &i.metadata,
353            Instruction::SRem(i) => &i.metadata,
354            Instruction::And(i) => &i.metadata,
355            Instruction::Or(i) => &i.metadata,
356            Instruction::Xor(i) => &i.metadata,
357            Instruction::Shl(i) => &i.metadata,
358            Instruction::LShr(i) => &i.metadata,
359            Instruction::AShr(i) => &i.metadata,
360            Instruction::FAdd(i) => &i.metadata,
361            Instruction::FSub(i) => &i.metadata,
362            Instruction::FMul(i) => &i.metadata,
363            Instruction::FDiv(i) => &i.metadata,
364            Instruction::FRem(i) => &i.metadata,
365            Instruction::FNeg(i) => &i.metadata,
366            Instruction::ExtractElement(i) => &i.metadata,
367            Instruction::InsertElement(i) => &i.metadata,
368            Instruction::ShuffleVector(i) => &i.metadata,
369            Instruction::ExtractValue(i) => &i.metadata,
370            Instruction::InsertValue(i) => &i.metadata,
371            Instruction::Alloca(i) => &i.metadata,
372            Instruction::Load(i) => &i.metadata,
373            Instruction::Store(i) => &i.metadata,
374            Instruction::Fence(i) => &i.metadata,
375            Instruction::CmpXchg(i) => &i.metadata,
376            Instruction::AtomicRMW(i) => &i.metadata,
377            Instruction::GetElementPtr(i) => &i.metadata,
378            Instruction::Trunc(i) => &i.metadata,
379            Instruction::ZExt(i) => &i.metadata,
380            Instruction::SExt(i) => &i.metadata,
381            Instruction::FPTrunc(i) => &i.metadata,
382            Instruction::FPExt(i) => &i.metadata,
383            Instruction::FPToUI(i) => &i.metadata,
384            Instruction::FPToSI(i) => &i.metadata,
385            Instruction::UIToFP(i) => &i.metadata,
386            Instruction::SIToFP(i) => &i.metadata,
387            Instruction::PtrToInt(i) => &i.metadata,
388            Instruction::IntToPtr(i) => &i.metadata,
389            Instruction::BitCast(i) => &i.metadata,
390            Instruction::AddrSpaceCast(i) => &i.metadata,
391            Instruction::ICmp(i) => &i.metadata,
392            Instruction::FCmp(i) => &i.metadata,
393            Instruction::Phi(i) => &i.metadata,
394            Instruction::Select(i) => &i.metadata,
395            #[cfg(feature="llvm-10-or-greater")]
396            Instruction::Freeze(i) => &i.metadata,
397            Instruction::Call(i) => &i.metadata,
398            Instruction::VAArg(i) => &i.metadata,
399            Instruction::LandingPad(i) => &i.metadata,
400            Instruction::CatchPad(i) => &i.metadata,
401            Instruction::CleanupPad(i) => &i.metadata,
402        }
403    }
404}
405*/
406
407pub trait HasResult: Debug + Typed {
408    fn get_result(&self) -> &Name;
409}
410
411pub trait UnaryOp: HasResult {
412    fn get_operand(&self) -> &Operand;
413}
414
415pub trait BinaryOp: HasResult {
416    fn get_operand0(&self) -> &Operand;
417    fn get_operand1(&self) -> &Operand;
418}
419
420pub mod groups;
421
422impl Instruction {
423    /// Determine if the `Instruction` is one of the ones in
424    /// [`groups::BinaryOp`](groups/enum.BinaryOp.html), without actually using
425    /// `try_into()` (which would consume it)
426    pub fn is_binary_op(&self) -> bool {
427        match self {
428            Instruction::Add(_) => true,
429            Instruction::Sub(_) => true,
430            Instruction::Mul(_) => true,
431            Instruction::UDiv(_) => true,
432            Instruction::SDiv(_) => true,
433            Instruction::URem(_) => true,
434            Instruction::SRem(_) => true,
435            Instruction::And(_) => true,
436            Instruction::Or(_) => true,
437            Instruction::Xor(_) => true,
438            Instruction::Shl(_) => true,
439            Instruction::LShr(_) => true,
440            Instruction::AShr(_) => true,
441            Instruction::FAdd(_) => true,
442            Instruction::FSub(_) => true,
443            Instruction::FMul(_) => true,
444            Instruction::FDiv(_) => true,
445            Instruction::FRem(_) => true,
446            _ => false,
447        }
448    }
449
450    /// Determine if the `Instruction` is one of the ones in
451    /// [`groups::UnaryOp`](groups/enum.UnaryOp.html), without actually using
452    /// `try_into()` (which would consume it)
453    pub fn is_unary_op(&self) -> bool {
454        match self {
455            Instruction::AddrSpaceCast(_) => true,
456            Instruction::BitCast(_) => true,
457            Instruction::FNeg(_) => true,
458            Instruction::FPExt(_) => true,
459            Instruction::FPToSI(_) => true,
460            Instruction::FPToUI(_) => true,
461            Instruction::FPTrunc(_) => true,
462            #[cfg(feature = "llvm-10-or-greater")]
463            Instruction::Freeze(_) => true,
464            Instruction::IntToPtr(_) => true,
465            Instruction::PtrToInt(_) => true,
466            Instruction::SExt(_) => true,
467            Instruction::SIToFP(_) => true,
468            Instruction::Trunc(_) => true,
469            Instruction::UIToFP(_) => true,
470            Instruction::ZExt(_) => true,
471            _ => false,
472        }
473    }
474}
475
476impl Display for Instruction {
477    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
478        match self {
479            Instruction::Add(i) => write!(f, "{}", i),
480            Instruction::Sub(i) => write!(f, "{}", i),
481            Instruction::Mul(i) => write!(f, "{}", i),
482            Instruction::UDiv(i) => write!(f, "{}", i),
483            Instruction::SDiv(i) => write!(f, "{}", i),
484            Instruction::URem(i) => write!(f, "{}", i),
485            Instruction::SRem(i) => write!(f, "{}", i),
486            Instruction::And(i) => write!(f, "{}", i),
487            Instruction::Or(i) => write!(f, "{}", i),
488            Instruction::Xor(i) => write!(f, "{}", i),
489            Instruction::Shl(i) => write!(f, "{}", i),
490            Instruction::LShr(i) => write!(f, "{}", i),
491            Instruction::AShr(i) => write!(f, "{}", i),
492            Instruction::FAdd(i) => write!(f, "{}", i),
493            Instruction::FSub(i) => write!(f, "{}", i),
494            Instruction::FMul(i) => write!(f, "{}", i),
495            Instruction::FDiv(i) => write!(f, "{}", i),
496            Instruction::FRem(i) => write!(f, "{}", i),
497            Instruction::FNeg(i) => write!(f, "{}", i),
498            Instruction::ExtractElement(i) => write!(f, "{}", i),
499            Instruction::InsertElement(i) => write!(f, "{}", i),
500            Instruction::ShuffleVector(i) => write!(f, "{}", i),
501            Instruction::ExtractValue(i) => write!(f, "{}", i),
502            Instruction::InsertValue(i) => write!(f, "{}", i),
503            Instruction::Alloca(i) => write!(f, "{}", i),
504            Instruction::Load(i) => write!(f, "{}", i),
505            Instruction::Store(i) => write!(f, "{}", i),
506            Instruction::Fence(i) => write!(f, "{}", i),
507            Instruction::CmpXchg(i) => write!(f, "{}", i),
508            Instruction::AtomicRMW(i) => write!(f, "{}", i),
509            Instruction::GetElementPtr(i) => write!(f, "{}", i),
510            Instruction::Trunc(i) => write!(f, "{}", i),
511            Instruction::ZExt(i) => write!(f, "{}", i),
512            Instruction::SExt(i) => write!(f, "{}", i),
513            Instruction::FPTrunc(i) => write!(f, "{}", i),
514            Instruction::FPExt(i) => write!(f, "{}", i),
515            Instruction::FPToUI(i) => write!(f, "{}", i),
516            Instruction::FPToSI(i) => write!(f, "{}", i),
517            Instruction::UIToFP(i) => write!(f, "{}", i),
518            Instruction::SIToFP(i) => write!(f, "{}", i),
519            Instruction::PtrToInt(i) => write!(f, "{}", i),
520            Instruction::IntToPtr(i) => write!(f, "{}", i),
521            Instruction::BitCast(i) => write!(f, "{}", i),
522            Instruction::AddrSpaceCast(i) => write!(f, "{}", i),
523            Instruction::ICmp(i) => write!(f, "{}", i),
524            Instruction::FCmp(i) => write!(f, "{}", i),
525            Instruction::Phi(i) => write!(f, "{}", i),
526            Instruction::Select(i) => write!(f, "{}", i),
527            #[cfg(feature = "llvm-10-or-greater")]
528            Instruction::Freeze(i) => write!(f, "{}", i),
529            Instruction::Call(i) => write!(f, "{}", i),
530            Instruction::VAArg(i) => write!(f, "{}", i),
531            Instruction::LandingPad(i) => write!(f, "{}", i),
532            Instruction::CatchPad(i) => write!(f, "{}", i),
533            Instruction::CleanupPad(i) => write!(f, "{}", i),
534        }
535    }
536}
537
538macro_rules! impl_inst {
539    ($inst:ty, $id:ident) => {
540        impl From<$inst> for Instruction {
541            fn from(inst: $inst) -> Instruction {
542                Instruction::$id(inst)
543            }
544        }
545
546        impl TryFrom<Instruction> for $inst {
547            type Error = &'static str;
548            fn try_from(inst: Instruction) -> Result<Self, Self::Error> {
549                match inst {
550                    Instruction::$id(inst) => Ok(inst),
551                    _ => Err("Instruction is not of requested type"),
552                }
553            }
554        }
555
556        impl HasDebugLoc for $inst {
557            fn get_debug_loc(&self) -> &Option<DebugLoc> {
558                &self.debugloc
559            }
560        }
561
562        /* --TODO not yet implemented: metadata
563        impl HasMetadata for $inst {
564            fn get_metadata(&self) -> &InstructionMetadata {
565                &self.metadata
566            }
567        }
568        */
569    };
570}
571
572macro_rules! impl_hasresult {
573    ($inst:ty) => {
574        impl HasResult for $inst {
575            fn get_result(&self) -> &Name {
576                &self.dest
577            }
578        }
579    };
580}
581
582// impls which are shared by all UnaryOps.
583// If possible, prefer `unop_same_type!` or `unop_explicitly_typed!`, which
584// provide additional impls
585macro_rules! impl_unop {
586    ($inst:ty) => {
587        impl_hasresult!($inst);
588
589        impl UnaryOp for $inst {
590            fn get_operand(&self) -> &Operand {
591                &self.operand
592            }
593        }
594    };
595}
596
597// impls which are shared by all BinaryOps
598macro_rules! impl_binop {
599    ($inst:ty, $id:ident) => {
600        impl_hasresult!($inst);
601
602        impl BinaryOp for $inst {
603            fn get_operand0(&self) -> &Operand {
604                &self.operand0
605            }
606            fn get_operand1(&self) -> &Operand {
607                &self.operand1
608            }
609        }
610
611        impl From<$inst> for groups::BinaryOp {
612            fn from(inst: $inst) -> Self {
613                groups::BinaryOp::$id(inst)
614            }
615        }
616
617        impl TryFrom<groups::BinaryOp> for $inst {
618            type Error = &'static str;
619            fn try_from(bo: groups::BinaryOp) -> Result<Self, Self::Error> {
620                match bo {
621                    groups::BinaryOp::$id(i) => Ok(i),
622                    _ => Err("BinaryOp is not of requested type"),
623                }
624            }
625        }
626    };
627}
628
629// Display impl for all BinaryOps that don't have nuw/nsw/exact flags
630macro_rules! binop_display {
631    ($inst:ty, $dispname:expr) => {
632        impl Display for $inst {
633            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
634                write!(
635                    f,
636                    "{} = {} {}, {}",
637                    &self.dest, $dispname, &self.operand0, &self.operand1,
638                )?;
639                if self.debugloc.is_some() {
640                    write!(f, " (with debugloc)")?;
641                }
642                Ok(())
643            }
644        }
645    };
646}
647
648// Display impl for all BinaryOps with nuw/nsw flags
649macro_rules! binop_nuw_nsw_display {
650    ($inst:ty, $dispname:expr) => {
651        impl Display for $inst {
652            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
653                #[cfg(feature = "llvm-16-or-lower")]
654                let nuw = "";
655                #[cfg(feature = "llvm-17-or-greater")]
656                let nuw = if self.nuw { " nuw" } else { "" };
657                #[cfg(feature = "llvm-16-or-lower")]
658                let nsw = "";
659                #[cfg(feature = "llvm-17-or-greater")]
660                let nsw = if self.nsw { " nsw" } else { "" };
661                write!(
662                    f,
663                    "{} = {}{}{} {}, {}",
664                    &self.dest,
665                    $dispname,
666                    nuw,
667                    nsw,
668                    &self.operand0,
669                    &self.operand1,
670                )?;
671                if self.debugloc.is_some() {
672                    write!(f, " (with debugloc)")?;
673                }
674                Ok(())
675            }
676        }
677    };
678}
679
680// Display impl for all BinaryOps with the 'exact' flag
681macro_rules! binop_exact_display {
682    ($inst:ty, $dispname:expr) => {
683        impl Display for $inst {
684            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
685                #[cfg(feature = "llvm-16-or-lower")]
686                let exact = "";
687                #[cfg(feature = "llvm-17-or-greater")]
688                let exact = if self.exact { " exact" } else { "" };
689                write!(
690                    f,
691                    "{} = {}{} {}, {}",
692                    &self.dest,
693                    $dispname,
694                    exact,
695                    &self.operand0,
696                    &self.operand1,
697                )?;
698                if self.debugloc.is_some() {
699                    write!(f, " (with debugloc)")?;
700                }
701                Ok(())
702            }
703        }
704    };
705}
706
707// Use on unops where the result type is the same as the operand type
708macro_rules! unop_same_type {
709    ($inst:ty, $dispname:expr) => {
710        impl_unop!($inst);
711
712        impl Typed for $inst {
713            fn get_type(&self, types: &Types) -> TypeRef {
714                types.type_of(self.get_operand())
715            }
716        }
717
718        impl Display for $inst {
719            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
720                write!(f, "{} = {} {}", &self.dest, $dispname, &self.operand)?;
721                if self.debugloc.is_some() {
722                    write!(f, " (with debugloc)")?;
723                }
724                Ok(())
725            }
726        }
727    };
728}
729
730// Use on unops with a `to_type` field which indicates the result type
731macro_rules! unop_explicitly_typed {
732    ($inst:ty, $dispname:expr) => {
733        impl_unop!($inst);
734        explicitly_typed!($inst);
735
736        impl Display for $inst {
737            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
738                write!(
739                    f,
740                    "{} = {} {} to {}",
741                    &self.dest, $dispname, &self.operand, &self.to_type,
742                )?;
743                if self.debugloc.is_some() {
744                    write!(f, " (with debugloc)")?;
745                }
746                Ok(())
747            }
748        }
749    };
750}
751
752// Use on binops where the result type is the same as both operand types
753macro_rules! binop_same_type {
754    ($inst:ty) => {
755        impl Typed for $inst {
756            fn get_type(&self, types: &Types) -> TypeRef {
757                let ty = types.type_of(self.get_operand0());
758                debug_assert_eq!(ty, types.type_of(self.get_operand1()));
759                ty
760            }
761        }
762    };
763}
764
765// Use on binops where the result type is the same as the first operand type
766macro_rules! binop_left_type {
767    ($inst:ty) => {
768        impl Typed for $inst {
769            fn get_type(&self, types: &Types) -> TypeRef {
770                types.type_of(self.get_operand0())
771            }
772        }
773    };
774}
775
776// Use on anything that has a 'to_type' field which indicates its result type
777macro_rules! explicitly_typed {
778    ($inst:ty) => {
779        impl Typed for $inst {
780            fn get_type(&self, _types: &Types) -> TypeRef {
781                self.to_type.clone()
782            }
783        }
784    };
785}
786
787macro_rules! void_typed {
788    ($inst:ty) => {
789        impl Typed for $inst {
790            fn get_type(&self, types: &Types) -> TypeRef {
791                types.void()
792            }
793        }
794    };
795}
796
797/// Integer add.
798/// See [LLVM 14 docs on the 'add' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#add-instruction)
799#[derive(PartialEq, Clone, Debug, Hash)]
800pub struct Add {
801    pub operand0: Operand,
802    pub operand1: Operand,
803    pub dest: Name,
804    #[cfg(feature = "llvm-17-or-greater")]
805    pub nuw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
806    #[cfg(feature = "llvm-17-or-greater")]
807    pub nsw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
808    pub debugloc: Option<DebugLoc>,
809    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
810}
811
812impl_inst!(Add, Add);
813impl_binop!(Add, Add);
814binop_same_type!(Add);
815binop_nuw_nsw_display!(Add, "add");
816
817/// Integer subtract.
818/// See [LLVM 14 docs on the 'sub' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#sub-instruction)
819#[derive(PartialEq, Clone, Debug, Hash)]
820pub struct Sub {
821    pub operand0: Operand,
822    pub operand1: Operand,
823    pub dest: Name,
824    #[cfg(feature = "llvm-17-or-greater")]
825    pub nuw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
826    #[cfg(feature = "llvm-17-or-greater")]
827    pub nsw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
828    pub debugloc: Option<DebugLoc>,
829    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
830}
831
832impl_inst!(Sub, Sub);
833impl_binop!(Sub, Sub);
834binop_same_type!(Sub);
835binop_nuw_nsw_display!(Sub, "sub");
836
837/// Integer multiply.
838/// See [LLVM 14 docs on the 'mul' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#mul-instruction)
839#[derive(PartialEq, Clone, Debug, Hash)]
840pub struct Mul {
841    pub operand0: Operand,
842    pub operand1: Operand,
843    pub dest: Name,
844    #[cfg(feature = "llvm-17-or-greater")]
845    pub nuw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
846    #[cfg(feature = "llvm-17-or-greater")]
847    pub nsw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
848    pub debugloc: Option<DebugLoc>,
849    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
850}
851
852impl_inst!(Mul, Mul);
853impl_binop!(Mul, Mul);
854binop_same_type!(Mul);
855binop_nuw_nsw_display!(Mul, "mul");
856
857/// Unsigned integer divide.
858/// See [LLVM 14 docs on the 'udiv' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#udiv-instruction)
859#[derive(PartialEq, Clone, Debug, Hash)]
860pub struct UDiv {
861    pub operand0: Operand,
862    pub operand1: Operand,
863    pub dest: Name,
864    #[cfg(feature = "llvm-17-or-greater")]
865    pub exact: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
866    pub debugloc: Option<DebugLoc>,
867    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
868}
869
870impl_inst!(UDiv, UDiv);
871impl_binop!(UDiv, UDiv);
872binop_same_type!(UDiv);
873binop_exact_display!(UDiv, "udiv");
874
875/// Signed integer divide.
876/// See [LLVM 14 docs on the 'sdiv' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#sdiv-instruction)
877#[derive(PartialEq, Clone, Debug, Hash)]
878pub struct SDiv {
879    pub operand0: Operand,
880    pub operand1: Operand,
881    pub dest: Name,
882    #[cfg(feature = "llvm-17-or-greater")]
883    pub exact: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
884    pub debugloc: Option<DebugLoc>,
885    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
886}
887
888impl_inst!(SDiv, SDiv);
889impl_binop!(SDiv, SDiv);
890binop_same_type!(SDiv);
891binop_exact_display!(SDiv, "sdiv");
892
893/// Unsigned integer remainder.
894/// See [LLVM 14 docs on the 'urem' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#urem-instruction)
895#[derive(PartialEq, Clone, Debug, Hash)]
896pub struct URem {
897    pub operand0: Operand,
898    pub operand1: Operand,
899    pub dest: Name,
900    pub debugloc: Option<DebugLoc>,
901    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
902}
903
904impl_inst!(URem, URem);
905impl_binop!(URem, URem);
906binop_same_type!(URem);
907binop_display!(URem, "urem");
908
909/// Signed integer remainder.
910/// See [LLVM 14 docs on the 'srem' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#srem-instruction)
911#[derive(PartialEq, Clone, Debug, Hash)]
912pub struct SRem {
913    pub operand0: Operand,
914    pub operand1: Operand,
915    pub dest: Name,
916    pub debugloc: Option<DebugLoc>,
917    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
918}
919
920impl_inst!(SRem, SRem);
921impl_binop!(SRem, SRem);
922binop_same_type!(SRem);
923binop_display!(SRem, "srem");
924
925/// Bitwise logical and.
926/// See [LLVM 14 docs on the 'and' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#and-instruction)
927#[derive(PartialEq, Clone, Debug, Hash)]
928pub struct And {
929    pub operand0: Operand,
930    pub operand1: Operand,
931    pub dest: Name,
932    pub debugloc: Option<DebugLoc>,
933    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
934}
935
936impl_inst!(And, And);
937impl_binop!(And, And);
938binop_same_type!(And);
939binop_display!(And, "and");
940
941/// Bitwise logical inclusive or.
942/// See [LLVM 14 docs on the 'or' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#or-instruction)
943#[derive(PartialEq, Clone, Debug, Hash)]
944pub struct Or {
945    pub operand0: Operand,
946    pub operand1: Operand,
947    pub dest: Name,
948    pub debugloc: Option<DebugLoc>,
949    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
950}
951
952impl_inst!(Or, Or);
953impl_binop!(Or, Or);
954binop_same_type!(Or);
955binop_display!(Or, "or");
956
957/// Bitwise logical exclusive or.
958/// See [LLVM 14 docs on the 'xor' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#xor-instruction)
959#[derive(PartialEq, Clone, Debug, Hash)]
960pub struct Xor {
961    pub operand0: Operand,
962    pub operand1: Operand,
963    pub dest: Name,
964    pub debugloc: Option<DebugLoc>,
965    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
966}
967
968impl_inst!(Xor, Xor);
969impl_binop!(Xor, Xor);
970binop_same_type!(Xor);
971binop_display!(Xor, "xor");
972
973/// Shift left.
974/// See [LLVM 14 docs on the 'shl' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#shl-instruction)
975#[derive(PartialEq, Clone, Debug, Hash)]
976pub struct Shl {
977    pub operand0: Operand,
978    pub operand1: Operand,
979    pub dest: Name,
980    #[cfg(feature = "llvm-17-or-greater")]
981    pub nuw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
982    #[cfg(feature = "llvm-17-or-greater")]
983    pub nsw: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
984    pub debugloc: Option<DebugLoc>,
985    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
986}
987
988impl_inst!(Shl, Shl);
989impl_binop!(Shl, Shl);
990binop_left_type!(Shl);
991binop_nuw_nsw_display!(Shl, "shl");
992
993/// Logical shift right.
994/// See [LLVM 14 docs on the 'lshr' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#lshr-instruction)
995#[derive(PartialEq, Clone, Debug, Hash)]
996pub struct LShr {
997    pub operand0: Operand,
998    pub operand1: Operand,
999    pub dest: Name,
1000    #[cfg(feature = "llvm-17-or-greater")]
1001    pub exact: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
1002    pub debugloc: Option<DebugLoc>,
1003    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1004}
1005
1006impl_inst!(LShr, LShr);
1007impl_binop!(LShr, LShr);
1008binop_left_type!(LShr);
1009binop_exact_display!(LShr, "lshr");
1010
1011/// Arithmetic shift right.
1012/// See [LLVM 14 docs on the 'ashr' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#ashr-instruction)
1013#[derive(PartialEq, Clone, Debug, Hash)]
1014pub struct AShr {
1015    pub operand0: Operand,
1016    pub operand1: Operand,
1017    pub dest: Name,
1018    #[cfg(feature = "llvm-17-or-greater")]
1019    pub exact: bool,  // prior to LLVM 17, no getter for this was exposed in the LLVM C API, only in the C++ one
1020    pub debugloc: Option<DebugLoc>,
1021    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1022}
1023
1024impl_inst!(AShr, AShr);
1025impl_binop!(AShr, AShr);
1026binop_left_type!(AShr);
1027binop_exact_display!(AShr, "ashr");
1028
1029/// Floating-point add.
1030/// See [LLVM 14 docs on the 'fadd' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fadd-instruction)
1031#[derive(PartialEq, Clone, Debug, Hash)]
1032pub struct FAdd {
1033    pub operand0: Operand,
1034    pub operand1: Operand,
1035    pub dest: Name,
1036    // pub fast_math_flags: FastMathFlags,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
1037    pub debugloc: Option<DebugLoc>,
1038    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1039}
1040
1041impl_inst!(FAdd, FAdd);
1042impl_binop!(FAdd, FAdd);
1043binop_same_type!(FAdd);
1044binop_display!(FAdd, "fadd");
1045
1046/// Floating-point subtract.
1047/// See [LLVM 14 docs on the 'fsub' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fsub-instruction)
1048#[derive(PartialEq, Clone, Debug, Hash)]
1049pub struct FSub {
1050    pub operand0: Operand,
1051    pub operand1: Operand,
1052    pub dest: Name,
1053    // pub fast_math_flags: FastMathFlags,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
1054    pub debugloc: Option<DebugLoc>,
1055    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1056}
1057
1058impl_inst!(FSub, FSub);
1059impl_binop!(FSub, FSub);
1060binop_same_type!(FSub);
1061binop_display!(FSub, "fsub");
1062
1063/// Floating-point multiply.
1064/// See [LLVM 14 docs on the 'fmul' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fmul-instruction)
1065#[derive(PartialEq, Clone, Debug, Hash)]
1066pub struct FMul {
1067    pub operand0: Operand,
1068    pub operand1: Operand,
1069    pub dest: Name,
1070    // pub fast_math_flags: FastMathFlags,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
1071    pub debugloc: Option<DebugLoc>,
1072    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1073}
1074
1075impl_inst!(FMul, FMul);
1076impl_binop!(FMul, FMul);
1077binop_same_type!(FMul);
1078binop_display!(FMul, "fmul");
1079
1080/// Floating-point divide.
1081/// See [LLVM 14 docs on the 'fdiv' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fdiv-instruction)
1082#[derive(PartialEq, Clone, Debug, Hash)]
1083pub struct FDiv {
1084    pub operand0: Operand,
1085    pub operand1: Operand,
1086    pub dest: Name,
1087    // pub fast_math_flags: FastMathFlags,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
1088    pub debugloc: Option<DebugLoc>,
1089    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1090}
1091
1092impl_inst!(FDiv, FDiv);
1093impl_binop!(FDiv, FDiv);
1094binop_same_type!(FDiv);
1095binop_display!(FDiv, "fdiv");
1096
1097/// Floating-point remainder.
1098/// See [LLVM 14 docs on the 'frem' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#frem-instruction)
1099#[derive(PartialEq, Clone, Debug, Hash)]
1100pub struct FRem {
1101    pub operand0: Operand,
1102    pub operand1: Operand,
1103    pub dest: Name,
1104    // pub fast_math_flags: FastMathFlags,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
1105    pub debugloc: Option<DebugLoc>,
1106    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1107}
1108
1109impl_inst!(FRem, FRem);
1110impl_binop!(FRem, FRem);
1111binop_same_type!(FRem);
1112binop_display!(FRem, "frem");
1113
1114/// Floating-point unary negation.
1115/// See [LLVM 14 docs on the 'fneg' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fneg-instruction)
1116#[derive(PartialEq, Clone, Debug, Hash)]
1117pub struct FNeg {
1118    pub operand: Operand,
1119    pub dest: Name,
1120    // pub fast_math_flags: FastMathFlags,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
1121    pub debugloc: Option<DebugLoc>,
1122    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1123}
1124
1125impl_inst!(FNeg, FNeg);
1126unop_same_type!(FNeg, "fneg");
1127
1128/// Get an element from a vector at a specified index.
1129/// See [LLVM 14 docs on the 'extractelement' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#extractelement-instruction)
1130#[derive(PartialEq, Clone, Debug, Hash)]
1131pub struct ExtractElement {
1132    pub vector: Operand,
1133    pub index: Operand,
1134    pub dest: Name,
1135    pub debugloc: Option<DebugLoc>,
1136    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1137}
1138
1139impl_inst!(ExtractElement, ExtractElement);
1140impl_hasresult!(ExtractElement);
1141
1142impl Typed for ExtractElement {
1143    fn get_type(&self, types: &Types) -> TypeRef {
1144        match types.type_of(&self.vector).as_ref() {
1145            Type::VectorType { element_type, .. } => element_type.clone(),
1146            ty => panic!(
1147                "Expected an ExtractElement vector to be VectorType, got {:?}",
1148                ty
1149            ),
1150        }
1151    }
1152}
1153
1154impl Display for ExtractElement {
1155    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1156        write!(
1157            f,
1158            "{} = extractelement {}, {}",
1159            &self.dest, &self.vector, &self.index,
1160        )?;
1161        if self.debugloc.is_some() {
1162            write!(f, " (with debugloc)")?;
1163        }
1164        Ok(())
1165    }
1166}
1167
1168/// Insert an element into a vector at a specified index.
1169/// See [LLVM 14 docs on the 'insertelement' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#insertelement-instruction)
1170#[derive(PartialEq, Clone, Debug, Hash)]
1171pub struct InsertElement {
1172    pub vector: Operand,
1173    pub element: Operand,
1174    pub index: Operand,
1175    pub dest: Name,
1176    pub debugloc: Option<DebugLoc>,
1177    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1178}
1179
1180impl_inst!(InsertElement, InsertElement);
1181impl_hasresult!(InsertElement);
1182
1183impl Typed for InsertElement {
1184    fn get_type(&self, types: &Types) -> TypeRef {
1185        types.type_of(&self.vector)
1186    }
1187}
1188
1189impl Display for InsertElement {
1190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1191        write!(
1192            f,
1193            "{} = insertelement {}, {}, {}",
1194            &self.dest, &self.vector, &self.element, &self.index,
1195        )?;
1196        if self.debugloc.is_some() {
1197            write!(f, " (with debugloc)")?;
1198        }
1199        Ok(())
1200    }
1201}
1202
1203/// Permute elements from two input vectors into a single output vector.
1204/// See [LLVM 14 docs on the 'shufflevector' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#shufflevector-instruction)
1205#[derive(PartialEq, Clone, Debug, Hash)]
1206pub struct ShuffleVector {
1207    pub operand0: Operand,
1208    pub operand1: Operand,
1209    pub dest: Name,
1210    pub mask: ConstantRef,
1211    pub debugloc: Option<DebugLoc>,
1212    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1213}
1214
1215impl_inst!(ShuffleVector, ShuffleVector);
1216impl_hasresult!(ShuffleVector);
1217
1218impl Typed for ShuffleVector {
1219    fn get_type(&self, types: &Types) -> TypeRef {
1220        let ty = types.type_of(&self.operand0);
1221        debug_assert_eq!(ty, types.type_of(&self.operand1));
1222        match ty.as_ref() {
1223            Type::VectorType { element_type, .. } => match types.type_of(&self.mask).as_ref() {
1224                #[cfg(feature = "llvm-11-or-greater")]
1225                Type::VectorType {
1226                    num_elements,
1227                    scalable,
1228                    ..
1229                } => types.vector_of(element_type.clone(), *num_elements, *scalable),
1230                #[cfg(feature = "llvm-10-or-lower")]
1231                Type::VectorType { num_elements, .. } => {
1232                    types.vector_of(element_type.clone(), *num_elements)
1233                },
1234                ty => panic!(
1235                    "Expected a ShuffleVector mask to be VectorType, got {:?}",
1236                    ty
1237                ),
1238            },
1239            _ => panic!(
1240                "Expected a ShuffleVector operand to be VectorType, got {:?}",
1241                ty
1242            ),
1243        }
1244    }
1245}
1246
1247impl Display for ShuffleVector {
1248    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1249        write!(
1250            f,
1251            "{} = shufflevector {}, {}, {}",
1252            &self.dest, &self.operand0, &self.operand1, &self.mask,
1253        )?;
1254        if self.debugloc.is_some() {
1255            write!(f, " (with debugloc)")?;
1256        }
1257        Ok(())
1258    }
1259}
1260
1261/// Extract the value of a member field from an aggregate (struct or array) type.
1262/// See [LLVM 14 docs on the 'extractvalue' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#extractvalue-instruction)
1263#[derive(PartialEq, Clone, Debug, Hash)]
1264pub struct ExtractValue {
1265    pub aggregate: Operand,
1266    pub indices: Vec<u32>,
1267    pub dest: Name,
1268    pub debugloc: Option<DebugLoc>,
1269    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1270}
1271
1272impl_inst!(ExtractValue, ExtractValue);
1273impl_hasresult!(ExtractValue);
1274
1275impl Typed for ExtractValue {
1276    fn get_type(&self, types: &Types) -> TypeRef {
1277        ev_type(types.type_of(&self.aggregate), self.indices.iter().copied())
1278    }
1279}
1280
1281fn ev_type(cur_type: TypeRef, mut indices: impl Iterator<Item = u32>) -> TypeRef {
1282    match indices.next() {
1283        None => cur_type,
1284        Some(index) => match cur_type.as_ref() {
1285            Type::ArrayType { element_type, .. } => ev_type(element_type.clone(), indices),
1286            Type::StructType { element_types, .. } => ev_type(
1287                element_types
1288                    .get(index as usize)
1289                    .expect("ExtractValue index out of range")
1290                    .clone(),
1291                indices,
1292            ),
1293            _ => panic!(
1294                "ExtractValue from something that's not ArrayType or StructType; its type is {:?}",
1295                cur_type
1296            ),
1297        },
1298    }
1299}
1300
1301impl Display for ExtractValue {
1302    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1303        write!(
1304            f,
1305            "{} = extractvalue {}, {}",
1306            &self.dest,
1307            &self.aggregate,
1308            &self.indices.first().expect("ExtractValue with no indices")
1309        )?;
1310        for idx in &self.indices[1 ..] {
1311            write!(f, ", {idx}")?;
1312        }
1313        if self.debugloc.is_some() {
1314            write!(f, " (with debugloc)")?;
1315        }
1316        Ok(())
1317    }
1318}
1319
1320/// Insert a value into a member field of an aggregate (struct or array) type.
1321/// See [LLVM 14 docs on the 'insertvalue' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#insertvalue-instruction)
1322#[derive(PartialEq, Clone, Debug, Hash)]
1323pub struct InsertValue {
1324    pub aggregate: Operand,
1325    pub element: Operand,
1326    pub indices: Vec<u32>,
1327    pub dest: Name,
1328    pub debugloc: Option<DebugLoc>,
1329    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1330}
1331
1332impl_inst!(InsertValue, InsertValue);
1333impl_hasresult!(InsertValue);
1334
1335impl Typed for InsertValue {
1336    fn get_type(&self, types: &Types) -> TypeRef {
1337        types.type_of(&self.aggregate)
1338    }
1339}
1340
1341impl Display for InsertValue {
1342    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1343        write!(
1344            f,
1345            "{} = insertvalue {}, {}, {}",
1346            &self.dest,
1347            &self.aggregate,
1348            &self.element,
1349            &self.indices.first().expect("InsertValue with no indices"),
1350        )?;
1351        for idx in &self.indices[1 ..] {
1352            write!(f, ", {idx}")?;
1353        }
1354        if self.debugloc.is_some() {
1355            write!(f, " (with debugloc)")?;
1356        }
1357        Ok(())
1358    }
1359}
1360
1361/// Allocate memory on the stack.
1362/// See [LLVM 14 docs on the 'alloca' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#alloca-instruction)
1363#[derive(PartialEq, Clone, Debug, Hash)]
1364pub struct Alloca {
1365    pub allocated_type: TypeRef,
1366    pub num_elements: Operand, // llvm-hs-pure has Option<Operand>
1367    pub dest: Name,
1368    pub alignment: u32,
1369    pub debugloc: Option<DebugLoc>,
1370    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1371}
1372
1373impl_inst!(Alloca, Alloca);
1374impl_hasresult!(Alloca);
1375
1376#[cfg(feature = "llvm-14-or-lower")]
1377impl Typed for Alloca {
1378    fn get_type(&self, types: &Types) -> TypeRef {
1379        types.pointer_to(self.allocated_type.clone())
1380    }
1381}
1382#[cfg(feature = "llvm-15-or-greater")]
1383impl Typed for Alloca {
1384    fn get_type(&self, types: &Types) -> TypeRef {
1385        types.pointer()
1386    }
1387}
1388
1389impl Display for Alloca {
1390    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1391        write!(f, "{} = alloca {}", &self.dest, &self.allocated_type)?;
1392        if let Some(Constant::Int { value: 1, .. }) = self.num_elements.as_constant() {
1393            // omit num_elements
1394        } else {
1395            write!(f, ", {}", &self.num_elements)?;
1396        }
1397        write!(f, ", align {}", &self.alignment)?;
1398        if self.debugloc.is_some() {
1399            write!(f, " (with debugloc)")?;
1400        }
1401        Ok(())
1402    }
1403}
1404
1405/// Load a value from memory.
1406/// See [LLVM 14 docs on the 'load' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#load-instruction)
1407#[derive(PartialEq, Clone, Debug, Hash)]
1408pub struct Load {
1409    pub address: Operand,
1410    pub dest: Name,
1411    #[cfg(feature = "llvm-15-or-greater")]
1412    pub loaded_ty: TypeRef,
1413    pub volatile: bool,
1414    pub atomicity: Option<Atomicity>,
1415    pub alignment: u32,
1416    pub debugloc: Option<DebugLoc>,
1417    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1418}
1419
1420impl_inst!(Load, Load);
1421impl_hasresult!(Load);
1422
1423#[cfg(feature = "llvm-14-or-lower")]
1424impl Typed for Load {
1425    fn get_type(&self, types: &Types) -> TypeRef {
1426        match types.type_of(&self.address).as_ref() {
1427            Type::PointerType { pointee_type, .. } => pointee_type.clone(),
1428            ty => panic!("Expected a load address to be PointerType, got {:?}", ty),
1429        }
1430    }
1431}
1432#[cfg(feature = "llvm-15-or-greater")]
1433impl Typed for Load {
1434    fn get_type(&self, _types: &Types) -> TypeRef {
1435        self.loaded_ty.clone()
1436    }
1437}
1438
1439impl Display for Load {
1440    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1441        write!(f, "{} = load ", &self.dest)?;
1442        if self.atomicity.is_some() {
1443            write!(f, "atomic ")?;
1444        }
1445        if self.volatile {
1446            write!(f, "volatile ")?;
1447        }
1448        #[cfg(feature = "llvm-14-or-lower")]
1449        {
1450            // we differ from the LLVM IR text syntax here because we don't include
1451            // the destination type (that's a little hard to get for us here, and
1452            // it's completely redundant with the address type anyway)
1453        }
1454        #[cfg(feature = "llvm-15-or-greater")]
1455        {
1456            write!(f, "{}, ", &self.loaded_ty)?;
1457        }
1458        write!(f, "{}", &self.address)?;
1459        if let Some(a) = &self.atomicity {
1460            write!(f, " {}", a)?;
1461        }
1462        write!(f, ", align {}", &self.alignment)?;
1463        if self.debugloc.is_some() {
1464            write!(f, " (with debugloc)")?;
1465        }
1466        Ok(())
1467    }
1468}
1469
1470/// Store a value to memory.
1471/// See [LLVM 14 docs on the 'store' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#store-instruction)
1472#[derive(PartialEq, Clone, Debug, Hash)]
1473pub struct Store {
1474    pub address: Operand,
1475    pub value: Operand,
1476    pub volatile: bool,
1477    pub atomicity: Option<Atomicity>,
1478    pub alignment: u32,
1479    pub debugloc: Option<DebugLoc>,
1480    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1481}
1482
1483impl_inst!(Store, Store);
1484void_typed!(Store);
1485
1486impl Display for Store {
1487    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1488        write!(f, "store ")?;
1489        if self.atomicity.is_some() {
1490            write!(f, "atomic ")?;
1491        }
1492        if self.volatile {
1493            write!(f, "volatile ")?;
1494        }
1495        write!(f, "{}, {}", &self.value, &self.address)?;
1496        if let Some(a) = &self.atomicity {
1497            write!(f, " {}", a)?;
1498        }
1499        write!(f, ", align {}", &self.alignment)?;
1500        if self.debugloc.is_some() {
1501            write!(f, " (with debugloc)")?;
1502        }
1503        Ok(())
1504    }
1505}
1506
1507/// Memory-ordering fence.
1508/// See [LLVM 14 docs on the 'fence' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fence-instruction)
1509#[derive(PartialEq, Clone, Debug, Hash)]
1510pub struct Fence {
1511    pub atomicity: Atomicity,
1512    pub debugloc: Option<DebugLoc>,
1513    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1514}
1515
1516impl_inst!(Fence, Fence);
1517void_typed!(Fence);
1518
1519impl Display for Fence {
1520    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1521        write!(f, "fence {}", &self.atomicity)?;
1522        if self.debugloc.is_some() {
1523            write!(f, " (with debugloc)")?;
1524        }
1525        Ok(())
1526    }
1527}
1528
1529/// Atomic compare and exchange.
1530/// See [LLVM 14 docs on the 'cmpxchg' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#cmpxchg-instruction)
1531#[derive(PartialEq, Clone, Debug, Hash)]
1532pub struct CmpXchg {
1533    pub address: Operand,
1534    pub expected: Operand,
1535    pub replacement: Operand,
1536    pub dest: Name,
1537    pub volatile: bool,
1538    /// This includes the "success" `MemoryOrdering`
1539    pub atomicity: Atomicity,
1540    /// This is the "failure" `MemoryOrdering`
1541    pub failure_memory_ordering: MemoryOrdering,
1542    #[cfg(feature = "llvm-10-or-greater")]
1543    pub weak: bool,
1544    pub debugloc: Option<DebugLoc>,
1545    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1546}
1547
1548impl_inst!(CmpXchg, CmpXchg);
1549impl_hasresult!(CmpXchg);
1550
1551impl Typed for CmpXchg {
1552    fn get_type(&self, types: &Types) -> TypeRef {
1553        let ty = types.type_of(&self.expected);
1554        debug_assert_eq!(ty, types.type_of(&self.replacement));
1555        types.struct_of(vec![ty, types.bool()], false)
1556    }
1557}
1558
1559impl Display for CmpXchg {
1560    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1561        write!(f, "{} = cmpxchg ", &self.dest)?;
1562        #[cfg(feature = "llvm-10-or-greater")]
1563        if self.weak {
1564            write!(f, "weak ")?;
1565        }
1566        if self.volatile {
1567            write!(f, "volatile ")?;
1568        }
1569        write!(
1570            f,
1571            "{}, {}, {} {} {}",
1572            &self.address,
1573            &self.expected,
1574            &self.replacement,
1575            &self.atomicity,
1576            &self.failure_memory_ordering,
1577        )?;
1578        if self.debugloc.is_some() {
1579            write!(f, " (with debugloc)")?;
1580        }
1581        Ok(())
1582    }
1583}
1584
1585/// Atomic read-modify-write.
1586/// See [LLVM 14 docs on the 'atomicrmw' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#atomicrmw-instruction)
1587#[derive(PartialEq, Clone, Debug, Hash)]
1588pub struct AtomicRMW {
1589    // the binop-getter was added to the LLVM C API in LLVM 10
1590    #[cfg(feature = "llvm-10-or-greater")]
1591    pub operation: RMWBinOp,
1592    pub address: Operand,
1593    pub value: Operand,
1594    pub dest: Name,
1595    pub volatile: bool,
1596    pub atomicity: Atomicity,
1597    pub debugloc: Option<DebugLoc>,
1598    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1599}
1600
1601impl_inst!(AtomicRMW, AtomicRMW);
1602impl_hasresult!(AtomicRMW);
1603
1604#[cfg(feature = "llvm-14-or-lower")]
1605impl Typed for AtomicRMW {
1606    fn get_type(&self, types: &Types) -> TypeRef {
1607        match types.type_of(&self.address).as_ref() {
1608            Type::PointerType { pointee_type, .. } => pointee_type.clone(),
1609            ty => panic!(
1610                "Expected an AtomicRMW address to be PointerType, got {:?}",
1611                ty
1612            ),
1613        }
1614    }
1615}
1616#[cfg(feature = "llvm-15-or-greater")]
1617impl Typed for AtomicRMW {
1618    fn get_type(&self, types: &Types) -> TypeRef {
1619        self.value.get_type(types)
1620    }
1621}
1622
1623impl Display for AtomicRMW {
1624    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1625        write!(f, "{} = atomicrmw ", &self.dest)?;
1626        if self.volatile {
1627            write!(f, "volatile ")?;
1628        }
1629        #[cfg(feature = "llvm-10-or-greater")]
1630        write!(f, "{} ", &self.operation)?;
1631        write!(f, "{}, {} {}", &self.address, &self.value, &self.atomicity)?;
1632        if self.debugloc.is_some() {
1633            write!(f, " (with debugloc)")?;
1634        }
1635        Ok(())
1636    }
1637}
1638
1639/// Get the address of a subelement of an aggregate data structure.
1640/// Only performs address calculation, does not actually access memory.
1641/// See [LLVM 14 docs on the 'getelementptr' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#getelementptr-instruction)
1642#[derive(PartialEq, Clone, Debug, Hash)]
1643pub struct GetElementPtr {
1644    pub address: Operand,
1645    pub indices: Vec<Operand>,
1646    pub dest: Name,
1647    pub in_bounds: bool,
1648    pub debugloc: Option<DebugLoc>,
1649    #[cfg(feature = "llvm-14-or-greater")]
1650    pub source_element_type: TypeRef
1651    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1652}
1653
1654impl_inst!(GetElementPtr, GetElementPtr);
1655impl_hasresult!(GetElementPtr);
1656
1657#[cfg(feature = "llvm-14-or-lower")]
1658impl Typed for GetElementPtr {
1659    fn get_type(&self, types: &Types) -> TypeRef {
1660        gep_type(types.type_of(&self.address), self.indices.iter(), types)
1661    }
1662}
1663#[cfg(feature = "llvm-15-or-greater")]
1664impl Typed for GetElementPtr {
1665    fn get_type(&self, types: &Types) -> TypeRef {
1666        types.pointer()
1667    }
1668}
1669
1670#[cfg(feature = "llvm-14-or-lower")]
1671fn gep_type<'o>(
1672    cur_type: TypeRef,
1673    mut indices: impl Iterator<Item = &'o Operand>,
1674    types: &Types,
1675) -> TypeRef {
1676    if let Type::NamedStructType { name } = cur_type.as_ref() {
1677        match types.named_struct_def(name) {
1678            None => panic!("Named struct without a definition (name {:?})", name),
1679            Some(NamedStructDef::Opaque) => {
1680                panic!("GEP on an opaque struct type (name {:?})", name)
1681            },
1682            Some(NamedStructDef::Defined(ty)) => {
1683                return gep_type(ty.clone(), indices, types);
1684            },
1685        }
1686    }
1687    match indices.next() {
1688        None => types.pointer_to(cur_type),  // iterator is done
1689        Some(index) => match cur_type.as_ref() {
1690            Type::PointerType { pointee_type, .. } => gep_type(pointee_type.clone(), indices, types),
1691            Type::VectorType { element_type, .. } => gep_type(element_type.clone(), indices, types),
1692            Type::ArrayType { element_type, .. } => gep_type(element_type.clone(), indices, types),
1693            Type::StructType { element_types, .. } => {
1694                if let Operand::ConstantOperand(cref) = index {
1695                    if let Constant::Int { value, .. } = cref.as_ref() {
1696                        gep_type(element_types.get(*value as usize).cloned().expect("GEP index out of range"), indices, types)
1697                    } else {
1698                        panic!("Expected GEP index on a struct to be a Constant::Int; got {:?}", cref)
1699                    }
1700                } else {
1701                    panic!("Expected GEP index on a struct to be a Operand::ConstantOperand(Constant::Int); got {:?}", index)
1702                }
1703            },
1704            Type::NamedStructType { .. } => panic!("This case should have been handled above"),
1705            _ => panic!("Expected GEP base type to be a PointerType, VectorType, ArrayType, StructType, or NamedStructType; got {:?}", cur_type),
1706        }
1707    }
1708}
1709
1710impl Display for GetElementPtr {
1711    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1712        // Like for `Load` (see notes there), we differ from the LLVM IR text
1713        // syntax here because we don't include the destination type (that's a
1714        // little hard to get for us here, and it's derivable from the other
1715        // information anyway)
1716        write!(f, "{} = getelementptr ", &self.dest)?;
1717        if self.in_bounds {
1718            write!(f, "inbounds ")?;
1719        }
1720        write!(f, "{}", &self.address)?;
1721        for idx in &self.indices {
1722            write!(f, ", {}", idx)?;
1723        }
1724        if self.debugloc.is_some() {
1725            write!(f, " (with debugloc)")?;
1726        }
1727        Ok(())
1728    }
1729}
1730
1731/// Truncate.
1732/// See [LLVM 14 docs on the 'trunc' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#trunc-to-instruction)
1733#[derive(PartialEq, Clone, Debug, Hash)]
1734pub struct Trunc {
1735    pub operand: Operand,
1736    pub to_type: TypeRef,
1737    pub dest: Name,
1738    pub debugloc: Option<DebugLoc>,
1739    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1740}
1741
1742impl_inst!(Trunc, Trunc);
1743unop_explicitly_typed!(Trunc, "trunc");
1744
1745/// Zero-extend.
1746/// See [LLVM 14 docs on the 'zext' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#zext-to-instruction)
1747#[derive(PartialEq, Clone, Debug, Hash)]
1748pub struct ZExt {
1749    pub operand: Operand,
1750    pub to_type: TypeRef,
1751    pub dest: Name,
1752    pub debugloc: Option<DebugLoc>,
1753    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1754}
1755
1756impl_inst!(ZExt, ZExt);
1757unop_explicitly_typed!(ZExt, "zext");
1758
1759/// Sign-extend.
1760/// See [LLVM 14 docs on the 'sext' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#sext-to-instruction)
1761#[derive(PartialEq, Clone, Debug, Hash)]
1762pub struct SExt {
1763    pub operand: Operand,
1764    pub to_type: TypeRef,
1765    pub dest: Name,
1766    pub debugloc: Option<DebugLoc>,
1767    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1768}
1769
1770impl_inst!(SExt, SExt);
1771unop_explicitly_typed!(SExt, "sext");
1772
1773/// Truncate a floating-point value.
1774/// See [LLVM 14 docs on the 'fptrunc' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fptrunc-to-instruction)
1775#[derive(PartialEq, Clone, Debug, Hash)]
1776pub struct FPTrunc {
1777    pub operand: Operand,
1778    pub to_type: TypeRef,
1779    pub dest: Name,
1780    pub debugloc: Option<DebugLoc>,
1781    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1782}
1783
1784impl_inst!(FPTrunc, FPTrunc);
1785unop_explicitly_typed!(FPTrunc, "fptrunc");
1786
1787/// Extend a floating-point value.
1788/// See [LLVM 14 docs on the 'fpext' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fpext-to-instruction)
1789#[derive(PartialEq, Clone, Debug, Hash)]
1790pub struct FPExt {
1791    pub operand: Operand,
1792    pub to_type: TypeRef,
1793    pub dest: Name,
1794    pub debugloc: Option<DebugLoc>,
1795    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1796}
1797
1798impl_inst!(FPExt, FPExt);
1799unop_explicitly_typed!(FPExt, "fpext");
1800
1801/// Convert floating-point to unsigned integer.
1802/// See [LLVM 14 docs on the 'fptoui' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fptoui-to-instruction)
1803#[derive(PartialEq, Clone, Debug, Hash)]
1804pub struct FPToUI {
1805    pub operand: Operand,
1806    pub to_type: TypeRef,
1807    pub dest: Name,
1808    pub debugloc: Option<DebugLoc>,
1809    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1810}
1811
1812impl_inst!(FPToUI, FPToUI);
1813unop_explicitly_typed!(FPToUI, "fptoui");
1814
1815/// Convert floating-point to signed integer.
1816/// See [LLVM 14 docs on the 'fptosi' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fptosi-to-instruction)
1817#[derive(PartialEq, Clone, Debug, Hash)]
1818pub struct FPToSI {
1819    pub operand: Operand,
1820    pub to_type: TypeRef,
1821    pub dest: Name,
1822    pub debugloc: Option<DebugLoc>,
1823    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1824}
1825
1826impl_inst!(FPToSI, FPToSI);
1827unop_explicitly_typed!(FPToSI, "fptosi");
1828
1829/// Convert unsigned integer to floating-point.
1830/// See [LLVM 14 docs on the 'uitofp' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#uitofp-to-instruction)
1831#[derive(PartialEq, Clone, Debug, Hash)]
1832pub struct UIToFP {
1833    pub operand: Operand,
1834    pub to_type: TypeRef,
1835    pub dest: Name,
1836    pub debugloc: Option<DebugLoc>,
1837    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1838}
1839
1840impl_inst!(UIToFP, UIToFP);
1841unop_explicitly_typed!(UIToFP, "uitofp");
1842
1843/// Convert signed integer to floating-point.
1844/// See [LLVM 14 docs on the 'sitofp' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#sitofp-to-instruction)
1845#[derive(PartialEq, Clone, Debug, Hash)]
1846pub struct SIToFP {
1847    pub operand: Operand,
1848    pub to_type: TypeRef,
1849    pub dest: Name,
1850    pub debugloc: Option<DebugLoc>,
1851    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1852}
1853
1854impl_inst!(SIToFP, SIToFP);
1855unop_explicitly_typed!(SIToFP, "sitofp");
1856
1857/// Convert pointer to integer.
1858/// See [LLVM 14 docs on the 'ptrtoint' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#ptrtoint-to-instruction)
1859#[derive(PartialEq, Clone, Debug, Hash)]
1860pub struct PtrToInt {
1861    pub operand: Operand,
1862    pub to_type: TypeRef,
1863    pub dest: Name,
1864    pub debugloc: Option<DebugLoc>,
1865    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1866}
1867
1868impl_inst!(PtrToInt, PtrToInt);
1869unop_explicitly_typed!(PtrToInt, "ptrtoint");
1870
1871/// Convert integer to pointer.
1872/// See [LLVM 14 docs on the 'inttoptr' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#inttoptr-to-instruction)
1873#[derive(PartialEq, Clone, Debug, Hash)]
1874pub struct IntToPtr {
1875    pub operand: Operand,
1876    pub to_type: TypeRef,
1877    pub dest: Name,
1878    pub debugloc: Option<DebugLoc>,
1879    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1880}
1881
1882impl_inst!(IntToPtr, IntToPtr);
1883unop_explicitly_typed!(IntToPtr, "inttoptr");
1884
1885/// Convert between types without changing any bits.
1886/// See [LLVM 14 docs on the 'bitcast' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#bitcast-to-instruction)
1887#[derive(PartialEq, Clone, Debug, Hash)]
1888pub struct BitCast {
1889    pub operand: Operand,
1890    pub to_type: TypeRef,
1891    pub dest: Name,
1892    pub debugloc: Option<DebugLoc>,
1893    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1894}
1895
1896impl_inst!(BitCast, BitCast);
1897unop_explicitly_typed!(BitCast, "bitcast");
1898
1899/// Convert a pointer to a different address space.
1900/// See [LLVM 14 docs on the 'addrspacecast' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#addrspacecast-to-instruction)
1901#[derive(PartialEq, Clone, Debug, Hash)]
1902pub struct AddrSpaceCast {
1903    pub operand: Operand,
1904    pub to_type: TypeRef,
1905    pub dest: Name,
1906    pub debugloc: Option<DebugLoc>,
1907    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1908}
1909
1910impl_inst!(AddrSpaceCast, AddrSpaceCast);
1911unop_explicitly_typed!(AddrSpaceCast, "addrspacecast");
1912
1913/// Compare integers, pointers, or vectors of integers or pointers.
1914/// See [LLVM 14 docs on the 'icmp' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#icmp-instruction)
1915#[derive(PartialEq, Clone, Debug, Hash)]
1916pub struct ICmp {
1917    pub predicate: IntPredicate,
1918    pub operand0: Operand,
1919    pub operand1: Operand,
1920    pub dest: Name,
1921    pub debugloc: Option<DebugLoc>,
1922    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1923}
1924
1925impl_inst!(ICmp, ICmp);
1926impl_hasresult!(ICmp);
1927
1928impl Typed for ICmp {
1929    fn get_type(&self, types: &Types) -> TypeRef {
1930        let ty = types.type_of(&self.operand0);
1931        debug_assert_eq!(ty, types.type_of(&self.operand1));
1932        match ty.as_ref() {
1933            #[cfg(feature = "llvm-11-or-greater")]
1934            Type::VectorType {
1935                num_elements,
1936                scalable,
1937                ..
1938            } => types.vector_of(types.bool(), *num_elements, *scalable),
1939            #[cfg(feature = "llvm-10-or-lower")]
1940            Type::VectorType { num_elements, .. } => types.vector_of(types.bool(), *num_elements),
1941            _ => types.bool(),
1942        }
1943    }
1944}
1945
1946impl Display for ICmp {
1947    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1948        write!(
1949            f,
1950            "{} = icmp {} {}, {}",
1951            &self.dest, &self.predicate, &self.operand0, &self.operand1,
1952        )?;
1953        if self.debugloc.is_some() {
1954            write!(f, " (with debugloc)")?;
1955        }
1956        Ok(())
1957    }
1958}
1959
1960/// Compare floating-point values or vectors of floating-point values.
1961/// See [LLVM 14 docs on the 'fcmp' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#fcmp-instruction)
1962#[derive(PartialEq, Clone, Debug, Hash)]
1963pub struct FCmp {
1964    pub predicate: FPPredicate,
1965    pub operand0: Operand,
1966    pub operand1: Operand,
1967    pub dest: Name,
1968    pub debugloc: Option<DebugLoc>,
1969    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
1970}
1971
1972impl_inst!(FCmp, FCmp);
1973impl_hasresult!(FCmp);
1974
1975impl Typed for FCmp {
1976    fn get_type(&self, types: &Types) -> TypeRef {
1977        let ty = types.type_of(&self.operand0);
1978        debug_assert_eq!(ty, types.type_of(&self.operand1));
1979        match ty.as_ref() {
1980            #[cfg(feature = "llvm-11-or-greater")]
1981            Type::VectorType {
1982                num_elements,
1983                scalable,
1984                ..
1985            } => types.vector_of(types.bool(), *num_elements, *scalable),
1986            #[cfg(feature = "llvm-10-or-lower")]
1987            Type::VectorType { num_elements, .. } => types.vector_of(types.bool(), *num_elements),
1988            _ => types.bool(),
1989        }
1990    }
1991}
1992
1993impl Display for FCmp {
1994    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1995        write!(
1996            f,
1997            "{} = fcmp {} {}, {}",
1998            &self.dest, &self.predicate, &self.operand0, &self.operand1,
1999        )?;
2000        if self.debugloc.is_some() {
2001            write!(f, " (with debugloc)")?;
2002        }
2003        Ok(())
2004    }
2005}
2006
2007/// See [LLVM 14 docs on the 'phi' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#phi-instruction)
2008#[derive(PartialEq, Clone, Debug, Hash)]
2009pub struct Phi {
2010    pub incoming_values: Vec<(Operand, Name)>,
2011    pub dest: Name,
2012    pub to_type: TypeRef,
2013    pub debugloc: Option<DebugLoc>,
2014    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2015}
2016
2017impl_inst!(Phi, Phi);
2018impl_hasresult!(Phi);
2019explicitly_typed!(Phi);
2020
2021impl Display for Phi {
2022    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2023        let (first_val, first_label) = &self
2024            .incoming_values
2025            .get(0)
2026            .expect("Phi with no incoming values");
2027        write!(
2028            f,
2029            "{} = phi {} [ {}, {} ]",
2030            &self.dest, &self.to_type, first_val, first_label,
2031        )?;
2032        for (val, label) in &self.incoming_values[1 ..] {
2033            write!(f, ", [ {}, {} ]", val, label)?;
2034        }
2035        if self.debugloc.is_some() {
2036            write!(f, " (with debugloc)")?;
2037        }
2038        Ok(())
2039    }
2040}
2041
2042/// Choose between two values depending on a condition.
2043/// See [LLVM 14 docs on the 'select' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#select-instruction)
2044#[derive(PartialEq, Clone, Debug, Hash)]
2045pub struct Select {
2046    pub condition: Operand,
2047    pub true_value: Operand,
2048    pub false_value: Operand,
2049    pub dest: Name,
2050    pub debugloc: Option<DebugLoc>,
2051    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2052}
2053
2054impl_inst!(Select, Select);
2055impl_hasresult!(Select);
2056
2057impl Typed for Select {
2058    fn get_type(&self, types: &Types) -> TypeRef {
2059        let t = types.type_of(&self.true_value);
2060        debug_assert_eq!(t, types.type_of(&self.false_value));
2061        t
2062    }
2063}
2064
2065impl Display for Select {
2066    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2067        write!(
2068            f,
2069            "{} = select {}, {}, {}",
2070            &self.dest, &self.condition, &self.true_value, &self.false_value,
2071        )?;
2072        if self.debugloc.is_some() {
2073            write!(f, " (with debugloc)")?;
2074        }
2075        Ok(())
2076    }
2077}
2078
2079/// Stop the propagation of `undef` or `poison` values.
2080/// See [LLVM 14 docs on the 'freeze' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#freeze-instruction)
2081#[cfg(feature = "llvm-10-or-greater")]
2082#[derive(PartialEq, Clone, Debug, Hash)]
2083pub struct Freeze {
2084    pub operand: Operand,
2085    pub dest: Name,
2086    pub debugloc: Option<DebugLoc>,
2087    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2088}
2089
2090#[cfg(feature = "llvm-10-or-greater")]
2091impl_inst!(Freeze, Freeze);
2092#[cfg(feature = "llvm-10-or-greater")]
2093unop_same_type!(Freeze, "freeze");
2094
2095/// Function call.
2096/// See [LLVM 14 docs on the 'call' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#call-instruction)
2097#[derive(PartialEq, Clone, Debug, Hash)]
2098pub struct Call {
2099    pub function: Either<InlineAssembly, Operand>,
2100    #[cfg(feature = "llvm-15-or-greater")]
2101    pub function_ty: TypeRef,
2102    pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
2103    pub return_attributes: Vec<ParameterAttribute>,
2104    pub dest: Option<Name>, // will be None if the `function` returns void
2105    pub function_attributes: Vec<FunctionAttribute>, // llvm-hs has the equivalent of Vec<Either<GroupID, FunctionAttribute>>, but I'm not sure how the GroupID option comes up
2106    pub is_tail_call: bool, // llvm-hs has the more sophisticated structure Option<TailCallKind>, but the LLVM C API just gives us true/false
2107    pub calling_convention: CallingConvention,
2108    pub debugloc: Option<DebugLoc>,
2109    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2110}
2111
2112impl_inst!(Call, Call);
2113
2114#[cfg(feature = "llvm-14-or-lower")]
2115impl Typed for Call {
2116    fn get_type(&self, types: &Types) -> TypeRef {
2117        match types.type_of(&self.function).as_ref() {
2118            Type::PointerType { pointee_type, .. } => match pointee_type.as_ref() {
2119                Type::FuncType { result_type, .. } => result_type.clone(),
2120                ty => panic!("Expected Call's function argument to be of type pointer-to-function, got pointer-to-{:?}", ty),
2121            },
2122            ty => panic!("Expected Call's function argument to be of type pointer-to-function, got {:?}", ty),
2123        }
2124    }
2125}
2126#[cfg(feature = "llvm-15-or-greater")]
2127impl Typed for Call {
2128    fn get_type(&self, _types: &Types) -> TypeRef {
2129        match self.function_ty.as_ref() {
2130            Type::FuncType { result_type, .. } => result_type.clone(),
2131            ty => panic!("Expected Call.function_ty to be a FuncType, got {:?}", ty),
2132        }
2133    }
2134}
2135
2136impl Display for Call {
2137    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2138        // We choose not to include all the detailed information available in
2139        // the `Call` struct in this `Display` impl
2140        if let Some(dest) = &self.dest {
2141            write!(f, "{} = ", dest)?;
2142        }
2143        if self.is_tail_call {
2144            write!(f, "tail ")?;
2145        }
2146        write!(
2147            f,
2148            "call {}(",
2149            match &self.function {
2150                Either::Left(_) => "<inline assembly>".into(),
2151                Either::Right(op) => format!("{}", op),
2152            }
2153        )?;
2154        for (i, (arg, _)) in self.arguments.iter().enumerate() {
2155            if i == self.arguments.len() - 1 {
2156                write!(f, "{}", arg)?;
2157            } else {
2158                write!(f, "{}, ", arg)?;
2159            }
2160        }
2161        write!(f, ")")?;
2162        if self.debugloc.is_some() {
2163            write!(f, " (with debugloc)")?;
2164        }
2165        Ok(())
2166    }
2167}
2168
2169/// Used to access variadic arguments passed to a function.
2170/// See [LLVM 14 docs on the 'va_arg' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#va-arg-instruction)
2171#[derive(PartialEq, Clone, Debug, Hash)]
2172pub struct VAArg {
2173    pub arg_list: Operand,
2174    pub cur_type: TypeRef,
2175    pub dest: Name,
2176    pub debugloc: Option<DebugLoc>,
2177    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2178}
2179
2180impl_inst!(VAArg, VAArg);
2181impl_hasresult!(VAArg);
2182
2183impl Typed for VAArg {
2184    fn get_type(&self, _types: &Types) -> TypeRef {
2185        self.cur_type.clone()
2186    }
2187}
2188
2189impl Display for VAArg {
2190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2191        write!(
2192            f,
2193            "{} = va_arg {}, {}",
2194            &self.dest, &self.arg_list, &self.cur_type,
2195        )?;
2196        if self.debugloc.is_some() {
2197            write!(f, " (with debugloc)")?;
2198        }
2199        Ok(())
2200    }
2201}
2202
2203/// Used for exception handling.
2204/// See [LLVM 14 docs on the 'landingpad' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#landingpad-instruction)
2205#[derive(PartialEq, Clone, Debug, Hash)]
2206pub struct LandingPad {
2207    pub result_type: TypeRef,
2208    pub clauses: Vec<LandingPadClause>,
2209    pub dest: Name,
2210    pub cleanup: bool,
2211    pub debugloc: Option<DebugLoc>,
2212    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2213}
2214
2215impl_inst!(LandingPad, LandingPad);
2216impl_hasresult!(LandingPad);
2217
2218impl Typed for LandingPad {
2219    fn get_type(&self, _types: &Types) -> TypeRef {
2220        self.result_type.clone()
2221    }
2222}
2223
2224impl Display for LandingPad {
2225    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2226        write!(f, "{} = landingpad {}", &self.dest, &self.result_type)?;
2227        if self.cleanup {
2228            write!(f, " cleanup")?;
2229        }
2230        if self.debugloc.is_some() {
2231            write!(f, " (with debugloc)")?;
2232        }
2233        Ok(())
2234    }
2235}
2236
2237/// Used for exception handling.
2238/// See [LLVM 14 docs on the 'catchpad' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#catchpad-instruction)
2239#[derive(PartialEq, Clone, Debug, Hash)]
2240pub struct CatchPad {
2241    pub catch_switch: Operand,
2242    pub args: Vec<Operand>,
2243    pub dest: Name,
2244    pub debugloc: Option<DebugLoc>,
2245    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2246}
2247
2248impl_inst!(CatchPad, CatchPad);
2249impl_hasresult!(CatchPad);
2250
2251impl Typed for CatchPad {
2252    fn get_type(&self, types: &Types) -> TypeRef {
2253        types.token_type()
2254    }
2255}
2256
2257impl Display for CatchPad {
2258    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2259        write!(
2260            f,
2261            "{} = catchpad within {} [",
2262            &self.dest, &self.catch_switch,
2263        )?;
2264        for (i, arg) in self.args.iter().enumerate() {
2265            if i == self.args.len() - 1 {
2266                write!(f, "{}", arg)?;
2267            } else {
2268                write!(f, "{}, ", arg)?;
2269            }
2270        }
2271        write!(f, "]")?;
2272        if self.debugloc.is_some() {
2273            write!(f, " (with debugloc)")?;
2274        }
2275        Ok(())
2276    }
2277}
2278
2279/// Used for exception handling.
2280/// See [LLVM 14 docs on the 'cleanuppad' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#cleanuppad-instruction)
2281#[derive(PartialEq, Clone, Debug, Hash)]
2282pub struct CleanupPad {
2283    pub parent_pad: Operand,
2284    pub args: Vec<Operand>,
2285    pub dest: Name,
2286    pub debugloc: Option<DebugLoc>,
2287    // --TODO not yet implemented-- pub metadata: InstructionMetadata,
2288}
2289
2290impl_inst!(CleanupPad, CleanupPad);
2291impl_hasresult!(CleanupPad);
2292
2293impl Typed for CleanupPad {
2294    fn get_type(&self, types: &Types) -> TypeRef {
2295        types.token_type()
2296    }
2297}
2298
2299impl Display for CleanupPad {
2300    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2301        write!(
2302            f,
2303            "{} = cleanuppad within {} [",
2304            &self.dest, &self.parent_pad,
2305        )?;
2306        for (i, arg) in self.args.iter().enumerate() {
2307            if i == self.args.len() - 1 {
2308                write!(f, "{}", arg)?;
2309            } else {
2310                write!(f, "{}, ", arg)?;
2311            }
2312        }
2313        write!(f, "]")?;
2314        if self.debugloc.is_some() {
2315            write!(f, " (with debugloc)")?;
2316        }
2317        Ok(())
2318    }
2319}
2320
2321/*
2322#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
2323pub enum TailCallKind {
2324    Tail,
2325    MustTail,
2326    NoTail,
2327}
2328*/
2329
2330/// See [LLVM 14 docs on Fast-Math Flags](https://releases.llvm.org/14.0.0/docs/LangRef.html#fastmath)
2331#[derive(PartialEq, Eq, Clone, Debug, Hash)]
2332#[allow(non_snake_case)]
2333pub struct FastMathFlags {
2334    pub allow_reassoc: bool,
2335    pub no_NaNs: bool,
2336    pub no_Infs: bool,
2337    pub no_signed_zeros: bool,
2338    pub allow_reciprocal: bool,
2339    pub allow_contract: bool,
2340    pub approx_func: bool,
2341}
2342
2343/// See [LLVM 14 docs on Atomic Memory Ordering Constraints](https://releases.llvm.org/14.0.0/docs/LangRef.html#ordering)
2344#[derive(PartialEq, Eq, Clone, Debug, Hash)]
2345pub struct Atomicity {
2346    pub synch_scope: SynchronizationScope,
2347    pub mem_ordering: MemoryOrdering,
2348}
2349
2350impl Display for Atomicity {
2351    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2352        match self.synch_scope {
2353            SynchronizationScope::SingleThread => write!(f, "syncscope(\"singlethread\") "),
2354            SynchronizationScope::System => Ok(()),
2355        }?;
2356        write!(f, "{}", &self.mem_ordering)?;
2357        Ok(())
2358    }
2359}
2360
2361/// See [LLVM 14 docs on Atomic Memory Ordering Constraints](https://releases.llvm.org/14.0.0/docs/LangRef.html#ordering)
2362#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
2363pub enum SynchronizationScope {
2364    SingleThread,
2365    System,
2366}
2367
2368/// See [LLVM 14 docs on Atomic Memory Ordering Constraints](https://releases.llvm.org/14.0.0/docs/LangRef.html#ordering)
2369#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
2370pub enum MemoryOrdering {
2371    Unordered,
2372    Monotonic,
2373    Acquire,
2374    Release,
2375    AcquireRelease,
2376    SequentiallyConsistent,
2377    NotAtomic, // since we only have a `MemoryOrdering` on atomic instructions, we should never need this. But empirically, some atomic instructions -- e.g. the first 'atomicrmw' instruction in our 'atomic_no_syncscope' test -- have this `MemoryOrdering`
2378}
2379
2380impl Display for MemoryOrdering {
2381    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2382        match self {
2383            MemoryOrdering::Unordered => write!(f, "unordered"),
2384            MemoryOrdering::Monotonic => write!(f, "monotonic"),
2385            MemoryOrdering::Acquire => write!(f, "acquire"),
2386            MemoryOrdering::Release => write!(f, "release"),
2387            MemoryOrdering::AcquireRelease => write!(f, "acq_rel"),
2388            MemoryOrdering::SequentiallyConsistent => write!(f, "seq_cst"),
2389            MemoryOrdering::NotAtomic => write!(f, "not_atomic"),
2390        }
2391    }
2392}
2393
2394// --TODO this seems to be the data structure we want. But see notes on
2395// InlineAssembly::from_llvm_ref()
2396/*
2397#[derive(PartialEq, Eq, Clone, Debug, Hash)]
2398pub struct InlineAssembly {
2399    pub assembly: String,
2400    pub ty: TypeRef,
2401    pub constraints: String,
2402    pub has_side_effects: bool,
2403    pub align_stack: bool,
2404    pub dialect: AssemblyDialect,
2405}
2406
2407#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
2408pub enum AssemblyDialect {
2409    ATT,
2410    Intel,
2411}
2412*/
2413// Instead we have this for now
2414/// See [LLVM 14 docs on Inline Assembler Expressions](https://releases.llvm.org/14.0.0/docs/LangRef.html#inline-assembler-expressions)
2415///
2416/// `InlineAssembly` needs more fields, but the necessary getter functions are
2417/// apparently not exposed in the LLVM C API (only the C++ API)
2418#[derive(PartialEq, Eq, Clone, Debug, Hash)]
2419pub struct InlineAssembly {
2420    pub ty: TypeRef,
2421}
2422
2423impl Typed for InlineAssembly {
2424    fn get_type(&self, _types: &Types) -> TypeRef {
2425        self.ty.clone()
2426    }
2427}
2428
2429/// See [LLVM 14 docs on the 'atomicrmw' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#i-atomicrmw)
2430#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
2431pub enum RMWBinOp {
2432    Xchg,
2433    Add,
2434    Sub,
2435    And,
2436    Nand,
2437    Or,
2438    Xor,
2439    Max,
2440    Min,
2441    UMax,
2442    UMin,
2443    #[cfg(feature = "llvm-10-or-greater")]
2444    FAdd,
2445    #[cfg(feature = "llvm-10-or-greater")]
2446    FSub,
2447    #[cfg(feature = "llvm-15-or-greater")]
2448    FMax,
2449    #[cfg(feature = "llvm-15-or-greater")]
2450    FMin,
2451    #[cfg(feature = "llvm-19-or-greater")]
2452    UIncWrap,
2453    #[cfg(feature = "llvm-19-or-greater")]
2454    UDecWrap,
2455}
2456
2457impl Display for RMWBinOp {
2458    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2459        match self {
2460            Self::Xchg => write!(f, "xchg"),
2461            Self::Add => write!(f, "add"),
2462            Self::Sub => write!(f, "sub"),
2463            Self::And => write!(f, "and"),
2464            Self::Nand => write!(f, "nand"),
2465            Self::Or => write!(f, "or"),
2466            Self::Xor => write!(f, "xor"),
2467            Self::Max => write!(f, "max"),
2468            Self::Min => write!(f, "min"),
2469            Self::UMax => write!(f, "umax"),
2470            Self::UMin => write!(f, "umin"),
2471            #[cfg(feature = "llvm-10-or-greater")]
2472            Self::FAdd => write!(f, "fadd"),
2473            #[cfg(feature = "llvm-10-or-greater")]
2474            Self::FSub => write!(f, "fsub"),
2475            #[cfg(feature = "llvm-15-or-greater")]
2476            Self::FMax => write!(f, "fmax"),
2477            #[cfg(feature = "llvm-15-or-greater")]
2478            Self::FMin => write!(f, "fmin"),
2479            #[cfg(feature = "llvm-19-or-greater")]
2480            Self::UIncWrap => write!(f, "uinc_wrap"),
2481            #[cfg(feature = "llvm-19-or-greater")]
2482            Self::UDecWrap => write!(f, "udec_wrap"),
2483        }
2484    }
2485}
2486
2487// --TODO this seems to be the data structure we want. But see notes on
2488// LandingPadClause::from_llvm_ref()
2489/*
2490#[derive(PartialEq, Clone, Debug, Hash)]
2491pub enum LandingPadClause {
2492    Catch(Constant),
2493    Filter(Constant),
2494}
2495*/
2496// Instead we have this for now
2497/// See [LLVM 14 docs on the 'landingpad' instruction](https://releases.llvm.org/14.0.0/docs/LangRef.html#landingpad-instruction)
2498///
2499/// `LandingPadClause` needs more fields, but the necessary getter functions are
2500/// apparently not exposed in the LLVM C API (only the C++ API)
2501#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
2502pub struct LandingPadClause {}
2503
2504// ********* //
2505// from_llvm //
2506// ********* //
2507
2508use crate::constant::Constant;
2509use crate::from_llvm::*;
2510use crate::function::FunctionContext;
2511use crate::llvm_sys::*;
2512use crate::module::ModuleContext;
2513use crate::types::TypesBuilder;
2514use llvm_sys::LLVMAtomicOrdering;
2515#[cfg(feature = "llvm-10-or-greater")]
2516use llvm_sys::LLVMAtomicRMWBinOp;
2517use llvm_sys::LLVMOpcode;
2518use llvm_sys::LLVMTypeKind::LLVMVoidTypeKind;
2519#[cfg(feature = "llvm-11-or-greater")]
2520use std::convert::TryInto;
2521
2522impl Instruction {
2523    pub(crate) fn from_llvm_ref(
2524        inst: LLVMValueRef,
2525        ctx: &mut ModuleContext,
2526        func_ctx: &mut FunctionContext,
2527    ) -> Self {
2528        debug!("Processing instruction {:?}", unsafe {
2529            print_to_string(inst)
2530        });
2531        match unsafe { LLVMGetInstructionOpcode(inst) } {
2532            LLVMOpcode::LLVMAdd => Instruction::Add(Add::from_llvm_ref(inst, ctx, func_ctx)),
2533            LLVMOpcode::LLVMSub => Instruction::Sub(Sub::from_llvm_ref(inst, ctx, func_ctx)),
2534            LLVMOpcode::LLVMMul => Instruction::Mul(Mul::from_llvm_ref(inst, ctx, func_ctx)),
2535            LLVMOpcode::LLVMUDiv => Instruction::UDiv(UDiv::from_llvm_ref(inst, ctx, func_ctx)),
2536            LLVMOpcode::LLVMSDiv => Instruction::SDiv(SDiv::from_llvm_ref(inst, ctx, func_ctx)),
2537            LLVMOpcode::LLVMURem => Instruction::URem(URem::from_llvm_ref(inst, ctx, func_ctx)),
2538            LLVMOpcode::LLVMSRem => Instruction::SRem(SRem::from_llvm_ref(inst, ctx, func_ctx)),
2539            LLVMOpcode::LLVMAnd => Instruction::And(And::from_llvm_ref(inst, ctx, func_ctx)),
2540            LLVMOpcode::LLVMOr => Instruction::Or(Or::from_llvm_ref(inst, ctx, func_ctx)),
2541            LLVMOpcode::LLVMXor => Instruction::Xor(Xor::from_llvm_ref(inst, ctx, func_ctx)),
2542            LLVMOpcode::LLVMShl => Instruction::Shl(Shl::from_llvm_ref(inst, ctx, func_ctx)),
2543            LLVMOpcode::LLVMLShr => Instruction::LShr(LShr::from_llvm_ref(inst, ctx, func_ctx)),
2544            LLVMOpcode::LLVMAShr => Instruction::AShr(AShr::from_llvm_ref(inst, ctx, func_ctx)),
2545            LLVMOpcode::LLVMFAdd => Instruction::FAdd(FAdd::from_llvm_ref(inst, ctx, func_ctx)),
2546            LLVMOpcode::LLVMFSub => Instruction::FSub(FSub::from_llvm_ref(inst, ctx, func_ctx)),
2547            LLVMOpcode::LLVMFMul => Instruction::FMul(FMul::from_llvm_ref(inst, ctx, func_ctx)),
2548            LLVMOpcode::LLVMFDiv => Instruction::FDiv(FDiv::from_llvm_ref(inst, ctx, func_ctx)),
2549            LLVMOpcode::LLVMFRem => Instruction::FRem(FRem::from_llvm_ref(inst, ctx, func_ctx)),
2550            LLVMOpcode::LLVMFNeg => Instruction::FNeg(FNeg::from_llvm_ref(inst, ctx, func_ctx)),
2551            LLVMOpcode::LLVMExtractElement => {
2552                Instruction::ExtractElement(ExtractElement::from_llvm_ref(inst, ctx, func_ctx))
2553            },
2554            LLVMOpcode::LLVMInsertElement => {
2555                Instruction::InsertElement(InsertElement::from_llvm_ref(inst, ctx, func_ctx))
2556            },
2557            LLVMOpcode::LLVMShuffleVector => {
2558                Instruction::ShuffleVector(ShuffleVector::from_llvm_ref(inst, ctx, func_ctx))
2559            },
2560            LLVMOpcode::LLVMExtractValue => {
2561                Instruction::ExtractValue(ExtractValue::from_llvm_ref(inst, ctx, func_ctx))
2562            },
2563            LLVMOpcode::LLVMInsertValue => {
2564                Instruction::InsertValue(InsertValue::from_llvm_ref(inst, ctx, func_ctx))
2565            },
2566            LLVMOpcode::LLVMAlloca => {
2567                Instruction::Alloca(Alloca::from_llvm_ref(inst, ctx, func_ctx))
2568            },
2569            LLVMOpcode::LLVMLoad => Instruction::Load(Load::from_llvm_ref(inst, ctx, func_ctx)),
2570            LLVMOpcode::LLVMStore => Instruction::Store(Store::from_llvm_ref(inst, ctx, func_ctx)),
2571            LLVMOpcode::LLVMFence => Instruction::Fence(Fence::from_llvm_ref(inst)),
2572            LLVMOpcode::LLVMAtomicCmpXchg => {
2573                Instruction::CmpXchg(CmpXchg::from_llvm_ref(inst, ctx, func_ctx))
2574            },
2575            LLVMOpcode::LLVMAtomicRMW => {
2576                Instruction::AtomicRMW(AtomicRMW::from_llvm_ref(inst, ctx, func_ctx))
2577            },
2578            LLVMOpcode::LLVMGetElementPtr => {
2579                Instruction::GetElementPtr(GetElementPtr::from_llvm_ref(inst, ctx, func_ctx))
2580            },
2581            LLVMOpcode::LLVMTrunc => Instruction::Trunc(Trunc::from_llvm_ref(inst, ctx, func_ctx)),
2582            LLVMOpcode::LLVMZExt => Instruction::ZExt(ZExt::from_llvm_ref(inst, ctx, func_ctx)),
2583            LLVMOpcode::LLVMSExt => Instruction::SExt(SExt::from_llvm_ref(inst, ctx, func_ctx)),
2584            LLVMOpcode::LLVMFPTrunc => {
2585                Instruction::FPTrunc(FPTrunc::from_llvm_ref(inst, ctx, func_ctx))
2586            },
2587            LLVMOpcode::LLVMFPExt => Instruction::FPExt(FPExt::from_llvm_ref(inst, ctx, func_ctx)),
2588            LLVMOpcode::LLVMFPToUI => {
2589                Instruction::FPToUI(FPToUI::from_llvm_ref(inst, ctx, func_ctx))
2590            },
2591            LLVMOpcode::LLVMFPToSI => {
2592                Instruction::FPToSI(FPToSI::from_llvm_ref(inst, ctx, func_ctx))
2593            },
2594            LLVMOpcode::LLVMUIToFP => {
2595                Instruction::UIToFP(UIToFP::from_llvm_ref(inst, ctx, func_ctx))
2596            },
2597            LLVMOpcode::LLVMSIToFP => {
2598                Instruction::SIToFP(SIToFP::from_llvm_ref(inst, ctx, func_ctx))
2599            },
2600            LLVMOpcode::LLVMPtrToInt => {
2601                Instruction::PtrToInt(PtrToInt::from_llvm_ref(inst, ctx, func_ctx))
2602            },
2603            LLVMOpcode::LLVMIntToPtr => {
2604                Instruction::IntToPtr(IntToPtr::from_llvm_ref(inst, ctx, func_ctx))
2605            },
2606            LLVMOpcode::LLVMBitCast => {
2607                Instruction::BitCast(BitCast::from_llvm_ref(inst, ctx, func_ctx))
2608            },
2609            LLVMOpcode::LLVMAddrSpaceCast => {
2610                Instruction::AddrSpaceCast(AddrSpaceCast::from_llvm_ref(inst, ctx, func_ctx))
2611            },
2612            LLVMOpcode::LLVMICmp => Instruction::ICmp(ICmp::from_llvm_ref(inst, ctx, func_ctx)),
2613            LLVMOpcode::LLVMFCmp => Instruction::FCmp(FCmp::from_llvm_ref(inst, ctx, func_ctx)),
2614            LLVMOpcode::LLVMPHI => Instruction::Phi(Phi::from_llvm_ref(inst, ctx, func_ctx)),
2615            LLVMOpcode::LLVMSelect => {
2616                Instruction::Select(Select::from_llvm_ref(inst, ctx, func_ctx))
2617            },
2618            #[cfg(feature = "llvm-10-or-greater")]
2619            LLVMOpcode::LLVMFreeze => {
2620                Instruction::Freeze(Freeze::from_llvm_ref(inst, ctx, func_ctx))
2621            },
2622            LLVMOpcode::LLVMCall => Instruction::Call(Call::from_llvm_ref(inst, ctx, func_ctx)),
2623            LLVMOpcode::LLVMVAArg => Instruction::VAArg(VAArg::from_llvm_ref(inst, ctx, func_ctx)),
2624            LLVMOpcode::LLVMLandingPad => {
2625                Instruction::LandingPad(LandingPad::from_llvm_ref(inst, ctx, func_ctx))
2626            },
2627            LLVMOpcode::LLVMCatchPad => {
2628                Instruction::CatchPad(CatchPad::from_llvm_ref(inst, ctx, func_ctx))
2629            },
2630            LLVMOpcode::LLVMCleanupPad => {
2631                Instruction::CleanupPad(CleanupPad::from_llvm_ref(inst, ctx, func_ctx))
2632            },
2633            opcode => panic!(
2634                "Instruction::from_llvm_ref called with a terminator instruction (opcode {:?})",
2635                opcode
2636            ),
2637        }
2638    }
2639}
2640
2641macro_rules! unop_from_llvm {
2642    ($inst:ident) => {
2643        impl $inst {
2644            pub(crate) fn from_llvm_ref(
2645                inst: LLVMValueRef,
2646                ctx: &mut ModuleContext,
2647                func_ctx: &mut FunctionContext,
2648            ) -> Self {
2649                assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
2650                Self {
2651                    operand: Operand::from_llvm_ref(
2652                        unsafe { LLVMGetOperand(inst, 0) },
2653                        ctx,
2654                        func_ctx,
2655                    ),
2656                    dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2657                    debugloc: DebugLoc::from_llvm_with_col(inst),
2658                    // metadata: InstructionMetadata::from_llvm_inst(inst),
2659                }
2660            }
2661        }
2662    };
2663}
2664
2665macro_rules! binop_from_llvm {
2666    ($inst:ident) => {
2667        impl $inst {
2668            pub(crate) fn from_llvm_ref(
2669                inst: LLVMValueRef,
2670                ctx: &mut ModuleContext,
2671                func_ctx: &mut FunctionContext,
2672            ) -> Self {
2673                assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
2674                Self {
2675                    operand0: Operand::from_llvm_ref(
2676                        unsafe { LLVMGetOperand(inst, 0) },
2677                        ctx,
2678                        func_ctx,
2679                    ),
2680                    operand1: Operand::from_llvm_ref(
2681                        unsafe { LLVMGetOperand(inst, 1) },
2682                        ctx,
2683                        func_ctx,
2684                    ),
2685                    dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2686                    debugloc: DebugLoc::from_llvm_with_col(inst),
2687                    // metadata: InstructionMetadata::from_llvm_inst(inst),
2688                }
2689            }
2690        }
2691    };
2692}
2693
2694macro_rules! binop_from_llvm_with_nuw_nsw {
2695    ($inst:ident) => {
2696        impl $inst {
2697            pub(crate) fn from_llvm_ref(
2698                inst: LLVMValueRef,
2699                ctx: &mut ModuleContext,
2700                func_ctx: &mut FunctionContext,
2701            ) -> Self {
2702                assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
2703                Self {
2704                    operand0: Operand::from_llvm_ref(
2705                        unsafe { LLVMGetOperand(inst, 0) },
2706                        ctx,
2707                        func_ctx,
2708                    ),
2709                    operand1: Operand::from_llvm_ref(
2710                        unsafe { LLVMGetOperand(inst, 1) },
2711                        ctx,
2712                        func_ctx,
2713                    ),
2714                    dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2715                    #[cfg(feature = "llvm-17-or-greater")]
2716                    nuw: unsafe { LLVMGetNUW(inst) } != 0,
2717                    #[cfg(feature = "llvm-17-or-greater")]
2718                    nsw: unsafe { LLVMGetNSW(inst) } != 0,
2719                    debugloc: DebugLoc::from_llvm_with_col(inst),
2720                    // metadata: InstructionMetadata::from_llvm_inst(inst),
2721                }
2722            }
2723        }
2724    };
2725}
2726
2727macro_rules! binop_from_llvm_with_exact {
2728    ($inst:ident) => {
2729        impl $inst {
2730            pub(crate) fn from_llvm_ref(
2731                inst: LLVMValueRef,
2732                ctx: &mut ModuleContext,
2733                func_ctx: &mut FunctionContext,
2734            ) -> Self {
2735                assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
2736                Self {
2737                    operand0: Operand::from_llvm_ref(
2738                        unsafe { LLVMGetOperand(inst, 0) },
2739                        ctx,
2740                        func_ctx,
2741                    ),
2742                    operand1: Operand::from_llvm_ref(
2743                        unsafe { LLVMGetOperand(inst, 1) },
2744                        ctx,
2745                        func_ctx,
2746                    ),
2747                    dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2748                    #[cfg(feature = "llvm-17-or-greater")]
2749                    exact: unsafe { LLVMGetExact(inst) } != 0,
2750                    debugloc: DebugLoc::from_llvm_with_col(inst),
2751                    // metadata: InstructionMetadata::from_llvm_inst(inst),
2752                }
2753            }
2754        }
2755    };
2756}
2757
2758binop_from_llvm_with_nuw_nsw!(Add);
2759binop_from_llvm_with_nuw_nsw!(Sub);
2760binop_from_llvm_with_nuw_nsw!(Mul);
2761binop_from_llvm_with_exact!(UDiv);
2762binop_from_llvm_with_exact!(SDiv);
2763binop_from_llvm!(URem);
2764binop_from_llvm!(SRem);
2765binop_from_llvm!(And);
2766binop_from_llvm!(Or);
2767binop_from_llvm!(Xor);
2768binop_from_llvm_with_nuw_nsw!(Shl);
2769binop_from_llvm_with_exact!(LShr);
2770binop_from_llvm_with_exact!(AShr);
2771binop_from_llvm!(FAdd);
2772binop_from_llvm!(FSub);
2773binop_from_llvm!(FMul);
2774binop_from_llvm!(FDiv);
2775binop_from_llvm!(FRem);
2776unop_from_llvm!(FNeg);
2777#[cfg(feature = "llvm-10-or-greater")]
2778unop_from_llvm!(Freeze);
2779
2780impl ExtractElement {
2781    pub(crate) fn from_llvm_ref(
2782        inst: LLVMValueRef,
2783        ctx: &mut ModuleContext,
2784        func_ctx: &mut FunctionContext,
2785    ) -> Self {
2786        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
2787        Self {
2788            vector: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
2789            index: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
2790            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2791            debugloc: DebugLoc::from_llvm_with_col(inst),
2792            // metadata: InstructionMetadata::from_llvm_inst(inst),
2793        }
2794    }
2795}
2796
2797impl InsertElement {
2798    pub(crate) fn from_llvm_ref(
2799        inst: LLVMValueRef,
2800        ctx: &mut ModuleContext,
2801        func_ctx: &mut FunctionContext,
2802    ) -> Self {
2803        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
2804        Self {
2805            vector: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
2806            element: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
2807            index: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx, func_ctx),
2808            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2809            debugloc: DebugLoc::from_llvm_with_col(inst),
2810            // metadata: InstructionMetadata::from_llvm_inst(inst),
2811        }
2812    }
2813}
2814
2815impl ShuffleVector {
2816    pub(crate) fn from_llvm_ref(
2817        inst: LLVMValueRef,
2818        ctx: &mut ModuleContext,
2819        func_ctx: &mut FunctionContext,
2820    ) -> Self {
2821        #[cfg(feature = "llvm-10-or-lower")]
2822        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
2823        #[cfg(feature = "llvm-11-or-greater")]
2824        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
2825        Self {
2826            operand0: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
2827            operand1: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
2828            #[cfg(feature = "llvm-10-or-lower")]
2829            mask: Constant::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx),
2830            #[cfg(feature = "llvm-11-or-greater")]
2831            mask: {
2832                let ret_ty = ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) });
2833                match ret_ty.as_ref() {
2834                    Type::VectorType { num_elements, scalable, .. } => {
2835                        assert_eq!(*num_elements as u32, unsafe { LLVMGetNumMaskElements(inst) });
2836                        let undef_elem = unsafe { LLVMGetUndefMaskElem() };
2837                        ConstantRef::new(Constant::Vector(
2838                            (0 .. *num_elements)
2839                                .map(|i| unsafe { LLVMGetMaskValue(inst, i.try_into().unwrap()) })
2840                                .map(|val| if val == undef_elem {
2841                                    Constant::Undef(ctx.types.i32())
2842                                } else {
2843                                    if *scalable {
2844                                        assert!(val == 0, "LLVM 11+ only allows zero or undef for mask elements in a ShuffleVector on scalable vectors");
2845                                    } else {
2846                                        assert!(val >= 0);
2847                                    }
2848                                    let val: u32 = val.try_into().unwrap();
2849                                    Constant::Int { value: val.into(), bits: 32 }
2850                                })
2851                                .map(ConstantRef::new)
2852                                .collect()
2853                        ))
2854                    },
2855                    ty => panic!("ShuffleVector: expected instruction result type to be a vector type; got {:?}", ty),
2856                }
2857            },
2858            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2859            debugloc: DebugLoc::from_llvm_with_col(inst),
2860            // metadata: InstructionMetadata::from_llvm_inst(inst),
2861        }
2862    }
2863}
2864
2865impl ExtractValue {
2866    pub(crate) fn from_llvm_ref(
2867        inst: LLVMValueRef,
2868        ctx: &mut ModuleContext,
2869        func_ctx: &mut FunctionContext,
2870    ) -> Self {
2871        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
2872        Self {
2873            aggregate: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
2874            indices: unsafe {
2875                let num_indices = LLVMGetNumIndices(inst);
2876                let ptr = LLVMGetIndices(inst);
2877                std::slice::from_raw_parts(ptr, num_indices as usize).to_vec()
2878            },
2879            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2880            debugloc: DebugLoc::from_llvm_with_col(inst),
2881            // metadata: InstructionMetadata::from_llvm_inst(inst),
2882        }
2883    }
2884}
2885
2886impl InsertValue {
2887    pub(crate) fn from_llvm_ref(
2888        inst: LLVMValueRef,
2889        ctx: &mut ModuleContext,
2890        func_ctx: &mut FunctionContext,
2891    ) -> Self {
2892        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
2893        Self {
2894            aggregate: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
2895            element: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
2896            indices: unsafe {
2897                let num_indices = LLVMGetNumIndices(inst);
2898                let ptr = LLVMGetIndices(inst);
2899                std::slice::from_raw_parts(ptr, num_indices as usize).to_vec()
2900            },
2901            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2902            debugloc: DebugLoc::from_llvm_with_col(inst),
2903            // metadata: InstructionMetadata::from_llvm_inst(inst),
2904        }
2905    }
2906}
2907
2908impl Alloca {
2909    pub(crate) fn from_llvm_ref(
2910        inst: LLVMValueRef,
2911        ctx: &mut ModuleContext,
2912        func_ctx: &mut FunctionContext,
2913    ) -> Self {
2914        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
2915        Self {
2916            allocated_type: ctx
2917                .types
2918                .type_from_llvm_ref(unsafe { LLVMGetAllocatedType(inst) }),
2919            num_elements: Operand::from_llvm_ref(
2920                unsafe { LLVMGetOperand(inst, 0) }, // This is a guess. or maybe num_elements is included in allocated_type?
2921                ctx,
2922                func_ctx,
2923            ),
2924            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2925            alignment: unsafe { LLVMGetAlignment(inst) },
2926            debugloc: DebugLoc::from_llvm_with_col(inst),
2927            // metadata: InstructionMetadata::from_llvm_inst(inst),
2928        }
2929    }
2930}
2931
2932impl Load {
2933    pub(crate) fn from_llvm_ref(
2934        inst: LLVMValueRef,
2935        ctx: &mut ModuleContext,
2936        func_ctx: &mut FunctionContext,
2937    ) -> Self {
2938        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
2939        Self {
2940            address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
2941            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
2942            #[cfg(feature = "llvm-15-or-greater")]
2943            loaded_ty: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
2944            volatile: unsafe { LLVMGetVolatile(inst) } != 0,
2945            atomicity: {
2946                let ordering = unsafe { LLVMGetOrdering(inst) };
2947                if ordering == LLVMAtomicOrdering::LLVMAtomicOrderingNotAtomic {
2948                    None
2949                } else {
2950                    Some(Atomicity {
2951                        synch_scope: SynchronizationScope::from_llvm_ref(inst),
2952                        mem_ordering: MemoryOrdering::from_llvm(ordering),
2953                    })
2954                }
2955            },
2956            alignment: unsafe { LLVMGetAlignment(inst) },
2957            debugloc: DebugLoc::from_llvm_with_col(inst),
2958            // metadata: InstructionMetadata::from_llvm_inst(inst),
2959        }
2960    }
2961}
2962
2963impl Store {
2964    pub(crate) fn from_llvm_ref(
2965        inst: LLVMValueRef,
2966        ctx: &mut ModuleContext,
2967        func_ctx: &mut FunctionContext,
2968    ) -> Self {
2969        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
2970        Self {
2971            address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
2972            value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
2973            volatile: unsafe { LLVMGetVolatile(inst) } != 0,
2974            atomicity: {
2975                let ordering = unsafe { LLVMGetOrdering(inst) };
2976                if ordering == LLVMAtomicOrdering::LLVMAtomicOrderingNotAtomic {
2977                    None
2978                } else {
2979                    Some(Atomicity {
2980                        synch_scope: SynchronizationScope::from_llvm_ref(inst),
2981                        mem_ordering: MemoryOrdering::from_llvm(ordering),
2982                    })
2983                }
2984            },
2985            alignment: unsafe { LLVMGetAlignment(inst) },
2986            debugloc: DebugLoc::from_llvm_with_col(inst),
2987            // metadata: InstructionMetadata::from_llvm_inst(inst),
2988        }
2989    }
2990}
2991
2992impl Fence {
2993    pub(crate) fn from_llvm_ref(inst: LLVMValueRef) -> Self {
2994        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 0);
2995        Self {
2996            atomicity: Atomicity {
2997                synch_scope: SynchronizationScope::from_llvm_ref(inst),
2998                mem_ordering: MemoryOrdering::from_llvm(unsafe { LLVMGetOrdering(inst) }),
2999            },
3000            debugloc: DebugLoc::from_llvm_with_col(inst),
3001            // metadata: InstructionMetadata::from_llvm_inst(inst),
3002        }
3003    }
3004}
3005
3006impl CmpXchg {
3007    pub(crate) fn from_llvm_ref(
3008        inst: LLVMValueRef,
3009        ctx: &mut ModuleContext,
3010        func_ctx: &mut FunctionContext,
3011    ) -> Self {
3012        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
3013        Self {
3014            address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3015            expected: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
3016            replacement: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx, func_ctx),
3017            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3018            volatile: unsafe { LLVMGetVolatile(inst) } != 0,
3019            atomicity: Atomicity {
3020                synch_scope: SynchronizationScope::from_llvm_ref(inst),
3021                mem_ordering: MemoryOrdering::from_llvm(unsafe {
3022                    LLVMGetCmpXchgSuccessOrdering(inst)
3023                }),
3024            },
3025            failure_memory_ordering: MemoryOrdering::from_llvm(unsafe {
3026                LLVMGetCmpXchgFailureOrdering(inst)
3027            }),
3028            #[cfg(feature = "llvm-10-or-greater")]
3029            weak: unsafe { LLVMGetWeak(inst) } != 0,
3030            debugloc: DebugLoc::from_llvm_with_col(inst),
3031            // metadata: InstructionMetadata::from_llvm_inst(inst),
3032        }
3033    }
3034}
3035
3036impl AtomicRMW {
3037    pub(crate) fn from_llvm_ref(
3038        inst: LLVMValueRef,
3039        ctx: &mut ModuleContext,
3040        func_ctx: &mut FunctionContext,
3041    ) -> Self {
3042        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
3043        Self {
3044            // the binop-getter was added to the LLVM C API in LLVM 10
3045            #[cfg(feature = "llvm-10-or-greater")]
3046            operation: RMWBinOp::from_llvm(unsafe { LLVMGetAtomicRMWBinOp(inst) }),
3047            address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3048            value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
3049            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3050            volatile: unsafe { LLVMGetVolatile(inst) } != 0,
3051            atomicity: Atomicity {
3052                synch_scope: SynchronizationScope::from_llvm_ref(inst),
3053                mem_ordering: MemoryOrdering::from_llvm(unsafe { LLVMGetOrdering(inst) }),
3054            },
3055            debugloc: DebugLoc::from_llvm_with_col(inst),
3056            // metadata: InstructionMetadata::from_llvm_inst(inst),
3057        }
3058    }
3059}
3060
3061impl GetElementPtr {
3062    pub(crate) fn from_llvm_ref(
3063        inst: LLVMValueRef,
3064        ctx: &mut ModuleContext,
3065        func_ctx: &mut FunctionContext,
3066    ) -> Self {
3067        Self {
3068            address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3069            indices: {
3070                let num_indices = unsafe { LLVMGetNumIndices(inst) };
3071                (1 ..= num_indices)
3072                    .map(|i| {
3073                        Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, i) }, ctx, func_ctx)
3074                    })
3075                    .collect()
3076            },
3077            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3078            in_bounds: unsafe { LLVMIsInBounds(inst) } != 0,
3079            debugloc: DebugLoc::from_llvm_with_col(inst),
3080            #[cfg(feature = "llvm-14-or-greater")]
3081            source_element_type: ctx.types.type_from_llvm_ref(unsafe { LLVMGetGEPSourceElementType(inst) }),
3082            // metadata: InstructionMetadata::from_llvm_inst(inst),
3083        }
3084    }
3085}
3086
3087// These instructions have the property that their result type is ambiguous from
3088//   knowing only their operands.
3089macro_rules! typed_unop_from_llvm {
3090    ($inst:ident) => {
3091        impl $inst {
3092            pub(crate) fn from_llvm_ref(
3093                inst: LLVMValueRef,
3094                ctx: &mut ModuleContext,
3095                func_ctx: &mut FunctionContext,
3096            ) -> Self {
3097                assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
3098                Self {
3099                    operand: Operand::from_llvm_ref(
3100                        unsafe { LLVMGetOperand(inst, 0) },
3101                        ctx,
3102                        func_ctx,
3103                    ),
3104                    to_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
3105                    dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3106                    debugloc: DebugLoc::from_llvm_with_col(inst),
3107                    // metadata: InstructionMetadata::from_llvm_inst(inst),
3108                }
3109            }
3110        }
3111    };
3112}
3113
3114typed_unop_from_llvm!(Trunc);
3115typed_unop_from_llvm!(ZExt);
3116typed_unop_from_llvm!(SExt);
3117typed_unop_from_llvm!(FPTrunc);
3118typed_unop_from_llvm!(FPExt);
3119typed_unop_from_llvm!(FPToUI);
3120typed_unop_from_llvm!(FPToSI);
3121typed_unop_from_llvm!(UIToFP);
3122typed_unop_from_llvm!(SIToFP);
3123typed_unop_from_llvm!(PtrToInt);
3124typed_unop_from_llvm!(IntToPtr);
3125typed_unop_from_llvm!(BitCast);
3126typed_unop_from_llvm!(AddrSpaceCast);
3127
3128impl ICmp {
3129    pub(crate) fn from_llvm_ref(
3130        inst: LLVMValueRef,
3131        ctx: &mut ModuleContext,
3132        func_ctx: &mut FunctionContext,
3133    ) -> Self {
3134        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
3135        Self {
3136            predicate: IntPredicate::from_llvm(unsafe { LLVMGetICmpPredicate(inst) }),
3137            operand0: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3138            operand1: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
3139            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3140            debugloc: DebugLoc::from_llvm_with_col(inst),
3141            // metadata: InstructionMetadata::from_llvm_inst(inst),
3142        }
3143    }
3144}
3145
3146impl FCmp {
3147    pub(crate) fn from_llvm_ref(
3148        inst: LLVMValueRef,
3149        ctx: &mut ModuleContext,
3150        func_ctx: &mut FunctionContext,
3151    ) -> Self {
3152        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
3153        Self {
3154            predicate: FPPredicate::from_llvm(unsafe { LLVMGetFCmpPredicate(inst) }),
3155            operand0: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3156            operand1: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
3157            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3158            debugloc: DebugLoc::from_llvm_with_col(inst),
3159            // metadata: InstructionMetadata::from_llvm_inst(inst),
3160        }
3161    }
3162}
3163
3164impl Phi {
3165    pub(crate) fn from_llvm_ref(
3166        inst: LLVMValueRef,
3167        ctx: &mut ModuleContext,
3168        func_ctx: &mut FunctionContext,
3169    ) -> Self {
3170        Self {
3171            incoming_values: {
3172                let num_incoming = unsafe { LLVMCountIncoming(inst) };
3173                (0 .. num_incoming)
3174                    .map(|i| {
3175                        let operand = Operand::from_llvm_ref(
3176                            unsafe { LLVMGetIncomingValue(inst, i) },
3177                            ctx,
3178                            func_ctx,
3179                        );
3180                        let name = func_ctx
3181                            .bb_names
3182                            .get(unsafe { &LLVMGetIncomingBlock(inst, i) })
3183                            .expect("Failed to find incoming block in the map")
3184                            .clone();
3185                        (operand, name)
3186                    })
3187                    .collect()
3188            },
3189            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3190            to_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
3191            debugloc: DebugLoc::from_llvm_with_col(inst),
3192            // metadata: InstructionMetadata::from_llvm_inst(inst),
3193        }
3194    }
3195}
3196
3197impl Select {
3198    pub(crate) fn from_llvm_ref(
3199        inst: LLVMValueRef,
3200        ctx: &mut ModuleContext,
3201        func_ctx: &mut FunctionContext,
3202    ) -> Self {
3203        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
3204        Self {
3205            condition: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3206            true_value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
3207            false_value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx, func_ctx),
3208            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3209            debugloc: DebugLoc::from_llvm_with_col(inst),
3210            // metadata: InstructionMetadata::from_llvm_inst(inst),
3211        }
3212    }
3213}
3214
3215// just the logic shared by Call and Invoke. Not a public struct, just an implementation convenience.
3216pub(crate) struct CallInfo {
3217    pub function: Either<InlineAssembly, Operand>,
3218    #[cfg(feature = "llvm-15-or-greater")]
3219    pub function_ty: TypeRef,
3220    pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
3221    pub return_attributes: Vec<ParameterAttribute>,
3222    pub function_attributes: Vec<FunctionAttribute>,
3223    pub calling_convention: CallingConvention,
3224}
3225
3226impl CallInfo {
3227    // Call this function only an a Call instruction or Invoke terminator
3228    pub(crate) fn from_llvm_ref(
3229        inst: LLVMValueRef,
3230        ctx: &mut ModuleContext,
3231        func_ctx: &mut FunctionContext,
3232    ) -> Self {
3233        use llvm_sys::{LLVMAttributeFunctionIndex, LLVMAttributeReturnIndex};
3234        let called_val = unsafe { LLVMGetCalledValue(inst) };
3235        Self {
3236            function: {
3237                let asm = unsafe { LLVMIsAInlineAsm(called_val) };
3238                if !asm.is_null() {
3239                    Either::Left(InlineAssembly::from_llvm_ref(asm, &mut ctx.types))
3240                } else {
3241                    Either::Right(Operand::from_llvm_ref(called_val, ctx, func_ctx))
3242                }
3243            },
3244            #[cfg(feature = "llvm-15-or-greater")]
3245            function_ty: ctx
3246                .types
3247                .type_from_llvm_ref(unsafe { LLVMGetCalledFunctionType(inst) }),
3248            arguments: {
3249                let num_args: u32 = unsafe { LLVMGetNumArgOperands(inst) } as u32;
3250                (0 .. num_args) // arguments are (0 .. num_args); other operands (such as the called function) are after that
3251                    .map(|i| {
3252                        let operand = Operand::from_llvm_ref(
3253                            unsafe { LLVMGetOperand(inst, i) },
3254                            ctx,
3255                            func_ctx,
3256                        );
3257                        let attrs = {
3258                            let num_attrs =
3259                                unsafe { LLVMGetCallSiteAttributeCount(inst, (i + 1) as u32) }; // see LLVM C API (Core.h) comments on `LLVMAttributeReturnIndex` and `LLVMAttributeFunctionIndex`
3260                            let mut attrs: Vec<LLVMAttributeRef> =
3261                                Vec::with_capacity(num_attrs as usize);
3262                            unsafe {
3263                                LLVMGetCallSiteAttributes(inst, (i + 1) as u32, attrs.as_mut_ptr());
3264                                attrs.set_len(num_attrs as usize);
3265                            };
3266                            attrs
3267                                .into_iter()
3268                                .map(|attr| {
3269                                    ParameterAttribute::from_llvm_ref(
3270                                        attr,
3271                                        &ctx.attrsdata,
3272                                        #[cfg(feature = "llvm-12-or-greater")]
3273                                        &mut ctx.types,
3274                                    )
3275                                })
3276                                .collect()
3277                        };
3278                        (operand, attrs)
3279                    })
3280                    .collect()
3281            },
3282            return_attributes: {
3283                let num_attrs =
3284                    unsafe { LLVMGetCallSiteAttributeCount(inst, LLVMAttributeReturnIndex) };
3285                let mut attrs: Vec<LLVMAttributeRef> = Vec::with_capacity(num_attrs as usize);
3286                unsafe {
3287                    LLVMGetCallSiteAttributes(inst, LLVMAttributeReturnIndex, attrs.as_mut_ptr());
3288                    attrs.set_len(num_attrs as usize);
3289                };
3290                attrs
3291                    .into_iter()
3292                    .map(|attr| {
3293                        ParameterAttribute::from_llvm_ref(
3294                            attr,
3295                            &ctx.attrsdata,
3296                            #[cfg(feature = "llvm-12-or-greater")]
3297                            &mut ctx.types,
3298                        )
3299                    })
3300                    .collect()
3301            },
3302            function_attributes: {
3303                let num_attrs =
3304                    unsafe { LLVMGetCallSiteAttributeCount(inst, LLVMAttributeFunctionIndex) };
3305                let mut attrs: Vec<LLVMAttributeRef> = Vec::with_capacity(num_attrs as usize);
3306                unsafe {
3307                    LLVMGetCallSiteAttributes(inst, LLVMAttributeFunctionIndex, attrs.as_mut_ptr());
3308                    attrs.set_len(num_attrs as usize);
3309                };
3310                attrs
3311                    .into_iter()
3312                    .map(|attr| FunctionAttribute::from_llvm_ref(attr, &ctx.attrsdata))
3313                    .collect()
3314            },
3315            calling_convention: CallingConvention::from_u32(unsafe {
3316                LLVMGetInstructionCallConv(inst)
3317            }),
3318        }
3319    }
3320}
3321
3322impl Call {
3323    pub(crate) fn from_llvm_ref(
3324        inst: LLVMValueRef,
3325        ctx: &mut ModuleContext,
3326        func_ctx: &mut FunctionContext,
3327    ) -> Self {
3328        let callinfo = CallInfo::from_llvm_ref(inst, ctx, func_ctx);
3329        Self {
3330            function: callinfo.function,
3331            #[cfg(feature = "llvm-15-or-greater")]
3332            function_ty: callinfo.function_ty,
3333            arguments: callinfo.arguments,
3334            return_attributes: callinfo.return_attributes,
3335            dest: if unsafe {
3336                LLVMGetTypeKind(LLVMGetReturnType(LLVMGetCalledFunctionType(inst)))
3337                    == LLVMVoidTypeKind
3338            } {
3339                None
3340            } else {
3341                Some(Name::name_or_num(
3342                    unsafe { get_value_name(inst) },
3343                    &mut func_ctx.ctr,
3344                ))
3345            },
3346            function_attributes: callinfo.function_attributes,
3347            is_tail_call: unsafe { LLVMIsTailCall(inst) } != 0,
3348            calling_convention: callinfo.calling_convention,
3349            debugloc: DebugLoc::from_llvm_with_col(inst),
3350            // metadata: InstructionMetadata::from_llvm_inst(inst),
3351        }
3352    }
3353}
3354
3355impl VAArg {
3356    pub(crate) fn from_llvm_ref(
3357        inst: LLVMValueRef,
3358        ctx: &mut ModuleContext,
3359        func_ctx: &mut FunctionContext,
3360    ) -> Self {
3361        assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
3362        Self {
3363            arg_list: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3364            cur_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
3365            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3366            debugloc: DebugLoc::from_llvm_with_col(inst),
3367            // metadata: InstructionMetadata::from_llvm_inst(inst),
3368        }
3369    }
3370}
3371
3372impl LandingPad {
3373    pub(crate) fn from_llvm_ref(
3374        inst: LLVMValueRef,
3375        ctx: &mut ModuleContext,
3376        func_ctx: &mut FunctionContext,
3377    ) -> Self {
3378        Self {
3379            result_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
3380            clauses: {
3381                let num_clauses = unsafe { LLVMGetNumClauses(inst) };
3382                (0 .. num_clauses)
3383                    .map(|i| LandingPadClause::from_llvm_ref(unsafe { LLVMGetClause(inst, i) }))
3384                    .collect()
3385            },
3386            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3387            cleanup: unsafe { LLVMIsCleanup(inst) } != 0,
3388            debugloc: DebugLoc::from_llvm_with_col(inst),
3389            // metadata: InstructionMetadata::from_llvm_inst(inst),
3390        }
3391    }
3392}
3393
3394impl CatchPad {
3395    pub(crate) fn from_llvm_ref(
3396        inst: LLVMValueRef,
3397        ctx: &mut ModuleContext,
3398        func_ctx: &mut FunctionContext,
3399    ) -> Self {
3400        Self {
3401            catch_switch: Operand::from_llvm_ref(
3402                unsafe { LLVMGetParentCatchSwitch(inst) },
3403                ctx,
3404                func_ctx,
3405            ),
3406            args: {
3407                let num_args = unsafe { LLVMGetNumArgOperands(inst) };
3408                (0 .. num_args)
3409                    .map(|i| {
3410                        Operand::from_llvm_ref(unsafe { LLVMGetArgOperand(inst, i) }, ctx, func_ctx)
3411                    })
3412                    .collect()
3413            },
3414            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3415            debugloc: DebugLoc::from_llvm_with_col(inst),
3416            // metadata: InstructionMetadata::from_llvm_inst(inst),
3417        }
3418    }
3419}
3420
3421impl CleanupPad {
3422    pub(crate) fn from_llvm_ref(
3423        inst: LLVMValueRef,
3424        ctx: &mut ModuleContext,
3425        func_ctx: &mut FunctionContext,
3426    ) -> Self {
3427        Self {
3428            parent_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
3429            args: {
3430                let num_args = unsafe { LLVMGetNumArgOperands(inst) };
3431                (0 .. num_args)
3432                    .map(|i| {
3433                        Operand::from_llvm_ref(unsafe { LLVMGetArgOperand(inst, i) }, ctx, func_ctx)
3434                    })
3435                    .collect()
3436            },
3437            dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
3438            debugloc: DebugLoc::from_llvm_with_col(inst),
3439            // metadata: InstructionMetadata::from_llvm_inst(inst),
3440        }
3441    }
3442}
3443
3444impl SynchronizationScope {
3445    pub(crate) fn from_llvm_ref(inst: LLVMValueRef) -> Self {
3446        if unsafe { LLVMIsAtomicSingleThread(inst) } != 0 {
3447            SynchronizationScope::SingleThread
3448        } else {
3449            SynchronizationScope::System
3450        }
3451    }
3452}
3453
3454impl MemoryOrdering {
3455    #[rustfmt::skip] // each one on one line, even if lines get a little long
3456    pub(crate) fn from_llvm(ao: LLVMAtomicOrdering) -> Self {
3457        match ao {
3458            LLVMAtomicOrdering::LLVMAtomicOrderingUnordered => MemoryOrdering::Unordered,
3459            LLVMAtomicOrdering::LLVMAtomicOrderingMonotonic => MemoryOrdering::Monotonic,
3460            LLVMAtomicOrdering::LLVMAtomicOrderingAcquire => MemoryOrdering::Acquire,
3461            LLVMAtomicOrdering::LLVMAtomicOrderingRelease => MemoryOrdering::Release,
3462            LLVMAtomicOrdering::LLVMAtomicOrderingAcquireRelease => MemoryOrdering::AcquireRelease,
3463            LLVMAtomicOrdering::LLVMAtomicOrderingSequentiallyConsistent => MemoryOrdering::SequentiallyConsistent,
3464            LLVMAtomicOrdering::LLVMAtomicOrderingNotAtomic => MemoryOrdering::NotAtomic,
3465        }
3466    }
3467}
3468
3469#[cfg(feature = "llvm-10-or-greater")]
3470impl RMWBinOp {
3471    pub(crate) fn from_llvm(rmwbo: LLVMAtomicRMWBinOp) -> Self {
3472        match rmwbo {
3473            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXchg => Self::Xchg,
3474            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd => Self::Add,
3475            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub => Self::Sub,
3476            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAnd => Self::And,
3477            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpNand => Self::Nand,
3478            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpOr => Self::Or,
3479            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXor => Self::Xor,
3480            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMax => Self::Max,
3481            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMin => Self::Min,
3482            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMax => Self::UMax,
3483            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMin => Self::UMin,
3484            #[cfg(feature = "llvm-10-or-greater")]
3485            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFAdd => Self::FAdd,
3486            #[cfg(feature = "llvm-10-or-greater")]
3487            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFSub => Self::FSub,
3488            #[cfg(feature = "llvm-15-or-greater")]
3489            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFMax => Self::FMax,
3490            #[cfg(feature = "llvm-15-or-greater")]
3491            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFMin => Self::FMin,
3492            #[cfg(feature = "llvm-19-or-greater")]
3493            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUIncWrap => Self::UIncWrap,
3494            #[cfg(feature = "llvm-19-or-greater")]
3495            LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUDecWrap => Self::UDecWrap,
3496        }
3497    }
3498}
3499
3500impl InlineAssembly {
3501    pub(crate) fn from_llvm_ref(asm: LLVMValueRef, types: &mut TypesBuilder) -> Self {
3502        // The LLVM C API appears to have no way to get any information about an
3503        // `InlineAssembly`? You can tell whether an `LLVMValueRef` is an
3504        // `InlineAssembly`, but once you know it is one, there seem to be no
3505        // other related methods
3506        Self {
3507            ty: types.type_from_llvm_ref(unsafe { LLVMTypeOf(asm) }),
3508        }
3509    }
3510}
3511
3512impl LandingPadClause {
3513    pub(crate) fn from_llvm_ref(_lpc: LLVMValueRef) -> Self {
3514        // The LLVM C API has an enum `LLVMLandingPadClauseTy`, but appears not
3515        // to reference it. In particular, it's unclear how to tell whether a
3516        // given clause is a `Catch` or a `Filter`.
3517        Self {}
3518    }
3519}