llvm_plugin_inkwell/values/
instruction_value.rs

1use either::{
2    Either,
3    Either::{Left, Right},
4};
5use llvm_sys::core::{
6    LLVMGetAlignment, LLVMGetFCmpPredicate, LLVMGetICmpPredicate, LLVMGetInstructionOpcode, LLVMGetInstructionParent,
7    LLVMGetMetadata, LLVMGetNextInstruction, LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse,
8    LLVMGetPreviousInstruction, LLVMGetVolatile, LLVMHasMetadata, LLVMInstructionClone, LLVMInstructionEraseFromParent,
9    LLVMInstructionRemoveFromParent, LLVMIsAAllocaInst, LLVMIsABasicBlock, LLVMIsALoadInst, LLVMIsAStoreInst,
10    LLVMIsTailCall, LLVMSetAlignment, LLVMSetMetadata, LLVMSetOperand, LLVMSetVolatile, LLVMValueAsBasicBlock,
11};
12use llvm_sys::core::{LLVMGetOrdering, LLVMSetOrdering};
13#[llvm_versions(10.0..=latest)]
14use llvm_sys::core::{LLVMIsAAtomicCmpXchgInst, LLVMIsAAtomicRMWInst};
15use llvm_sys::prelude::LLVMValueRef;
16use llvm_sys::LLVMOpcode;
17
18use std::{ffi::CStr, fmt, fmt::Display};
19
20use crate::values::traits::AsValueRef;
21use crate::values::{BasicValue, BasicValueEnum, BasicValueUse, MetadataValue, Value};
22use crate::{basic_block::BasicBlock, types::AnyTypeEnum};
23use crate::{AtomicOrdering, FloatPredicate, IntPredicate};
24
25use super::AnyValue;
26
27// REVIEW: Split up into structs for SubTypes on InstructionValues?
28// REVIEW: This should maybe be split up into InstructionOpcode and ConstOpcode?
29// see LLVMGetConstOpcode
30#[llvm_enum(LLVMOpcode)]
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum InstructionOpcode {
33    // Actual Instructions:
34    Add,
35    AddrSpaceCast,
36    Alloca,
37    And,
38    AShr,
39    AtomicCmpXchg,
40    AtomicRMW,
41    BitCast,
42    Br,
43    Call,
44    #[llvm_versions(9.0..=latest)]
45    CallBr,
46    CatchPad,
47    CatchRet,
48    CatchSwitch,
49    CleanupPad,
50    CleanupRet,
51    ExtractElement,
52    ExtractValue,
53    #[llvm_versions(8.0..=latest)]
54    FNeg,
55    FAdd,
56    FCmp,
57    FDiv,
58    Fence,
59    FMul,
60    FPExt,
61    FPToSI,
62    FPToUI,
63    FPTrunc,
64    #[llvm_versions(10.0..=latest)]
65    Freeze,
66    FRem,
67    FSub,
68    GetElementPtr,
69    ICmp,
70    IndirectBr,
71    InsertElement,
72    InsertValue,
73    IntToPtr,
74    Invoke,
75    LandingPad,
76    Load,
77    LShr,
78    Mul,
79    Or,
80    #[llvm_variant(LLVMPHI)]
81    Phi,
82    PtrToInt,
83    Resume,
84    #[llvm_variant(LLVMRet)]
85    Return,
86    SDiv,
87    Select,
88    SExt,
89    Shl,
90    ShuffleVector,
91    SIToFP,
92    SRem,
93    Store,
94    Sub,
95    Switch,
96    Trunc,
97    UDiv,
98    UIToFP,
99    Unreachable,
100    URem,
101    UserOp1,
102    UserOp2,
103    VAArg,
104    Xor,
105    ZExt,
106}
107
108#[derive(Debug, PartialEq, Eq, Copy, Hash)]
109pub struct InstructionValue<'ctx> {
110    instruction_value: Value<'ctx>,
111}
112
113impl<'ctx> InstructionValue<'ctx> {
114    fn is_a_load_inst(self) -> bool {
115        !unsafe { LLVMIsALoadInst(self.as_value_ref()) }.is_null()
116    }
117    fn is_a_store_inst(self) -> bool {
118        !unsafe { LLVMIsAStoreInst(self.as_value_ref()) }.is_null()
119    }
120    fn is_a_alloca_inst(self) -> bool {
121        !unsafe { LLVMIsAAllocaInst(self.as_value_ref()) }.is_null()
122    }
123    #[llvm_versions(10.0..=latest)]
124    fn is_a_atomicrmw_inst(self) -> bool {
125        !unsafe { LLVMIsAAtomicRMWInst(self.as_value_ref()) }.is_null()
126    }
127    #[llvm_versions(10.0..=latest)]
128    fn is_a_cmpxchg_inst(self) -> bool {
129        !unsafe { LLVMIsAAtomicCmpXchgInst(self.as_value_ref()) }.is_null()
130    }
131
132    pub(crate) unsafe fn new(instruction_value: LLVMValueRef) -> Self {
133        debug_assert!(!instruction_value.is_null());
134
135        let value = Value::new(instruction_value);
136
137        debug_assert!(value.is_instruction());
138
139        InstructionValue {
140            instruction_value: value,
141        }
142    }
143
144    /// Get name of the `InstructionValue`.
145    pub fn get_name(&self) -> Option<&CStr> {
146        if self.get_type().is_void_type() {
147            None
148        } else {
149            Some(self.instruction_value.get_name())
150        }
151    }
152
153    /// Set name of the `InstructionValue`.
154    pub fn set_name(&self, name: &str) -> Result<(), &'static str> {
155        if self.get_type().is_void_type() {
156            Err("Cannot set name of a void-type instruction!")
157        } else {
158            self.instruction_value.set_name(name);
159            Ok(())
160        }
161    }
162
163    /// Get type of the current InstructionValue
164    pub fn get_type(self) -> AnyTypeEnum<'ctx> {
165        unsafe { AnyTypeEnum::new(self.instruction_value.get_type()) }
166    }
167
168    pub fn get_opcode(self) -> InstructionOpcode {
169        let opcode = unsafe { LLVMGetInstructionOpcode(self.as_value_ref()) };
170
171        InstructionOpcode::new(opcode)
172    }
173
174    pub fn get_previous_instruction(self) -> Option<Self> {
175        let value = unsafe { LLVMGetPreviousInstruction(self.as_value_ref()) };
176
177        if value.is_null() {
178            return None;
179        }
180
181        unsafe { Some(InstructionValue::new(value)) }
182    }
183
184    pub fn get_next_instruction(self) -> Option<Self> {
185        let value = unsafe { LLVMGetNextInstruction(self.as_value_ref()) };
186
187        if value.is_null() {
188            return None;
189        }
190
191        unsafe { Some(InstructionValue::new(value)) }
192    }
193
194    // REVIEW: Potentially unsafe if parent BB or grandparent fn were removed?
195    pub fn erase_from_basic_block(self) {
196        unsafe { LLVMInstructionEraseFromParent(self.as_value_ref()) }
197    }
198
199    // REVIEW: Potentially unsafe if parent BB or grandparent fn were removed?
200    #[llvm_versions(4.0..=latest)]
201    pub fn remove_from_basic_block(self) {
202        unsafe { LLVMInstructionRemoveFromParent(self.as_value_ref()) }
203    }
204
205    // REVIEW: Potentially unsafe is parent BB or grandparent fn was deleted
206    // REVIEW: Should this *not* be an option? Parent should always exist,
207    // but I doubt LLVM returns null if the parent BB (or grandparent FN)
208    // was deleted... Invalid memory is more likely. Cloned IV will have no
209    // parent?
210    pub fn get_parent(self) -> Option<BasicBlock<'ctx>> {
211        unsafe { BasicBlock::new(LLVMGetInstructionParent(self.as_value_ref())) }
212    }
213
214    pub fn is_tail_call(self) -> bool {
215        // LLVMIsTailCall has UB if the value is not an llvm::CallInst*.
216        if self.get_opcode() == InstructionOpcode::Call {
217            unsafe { LLVMIsTailCall(self.as_value_ref()) == 1 }
218        } else {
219            false
220        }
221    }
222
223    pub fn replace_all_uses_with(self, other: &InstructionValue<'ctx>) {
224        self.instruction_value.replace_all_uses_with(other.as_value_ref())
225    }
226
227    // SubTypes: Only apply to memory access instructions
228    /// Returns whether or not a memory access instruction is volatile.
229    #[llvm_versions(4.0..=9.0)]
230    pub fn get_volatile(self) -> Result<bool, &'static str> {
231        // Although cmpxchg and atomicrmw can have volatile, LLVM's C API
232        // does not export that functionality until 10.0.
233        if !self.is_a_load_inst() && !self.is_a_store_inst() {
234            return Err("Value is not a load or store.");
235        }
236        Ok(unsafe { LLVMGetVolatile(self.as_value_ref()) } == 1)
237    }
238
239    // SubTypes: Only apply to memory access instructions
240    /// Returns whether or not a memory access instruction is volatile.
241    #[llvm_versions(10.0..=latest)]
242    pub fn get_volatile(self) -> Result<bool, &'static str> {
243        if !self.is_a_load_inst() && !self.is_a_store_inst() && !self.is_a_atomicrmw_inst() && !self.is_a_cmpxchg_inst()
244        {
245            return Err("Value is not a load, store, atomicrmw or cmpxchg.");
246        }
247        Ok(unsafe { LLVMGetVolatile(self.as_value_ref()) } == 1)
248    }
249
250    // SubTypes: Only apply to memory access instructions
251    /// Sets whether or not a memory access instruction is volatile.
252    #[llvm_versions(4.0..=9.0)]
253    pub fn set_volatile(self, volatile: bool) -> Result<(), &'static str> {
254        // Although cmpxchg and atomicrmw can have volatile, LLVM's C API
255        // does not export that functionality until 10.0.
256        if !self.is_a_load_inst() && !self.is_a_store_inst() {
257            return Err("Value is not a load or store.");
258        }
259        Ok(unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) })
260    }
261
262    // SubTypes: Only apply to memory access instructions
263    /// Sets whether or not a memory access instruction is volatile.
264    #[llvm_versions(10.0..=latest)]
265    pub fn set_volatile(self, volatile: bool) -> Result<(), &'static str> {
266        if !self.is_a_load_inst() && !self.is_a_store_inst() && !self.is_a_atomicrmw_inst() && !self.is_a_cmpxchg_inst()
267        {
268            return Err("Value is not a load, store, atomicrmw or cmpxchg.");
269        }
270        unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) };
271        Ok(())
272    }
273
274    // SubTypes: Only apply to memory access and alloca instructions
275    /// Returns alignment on a memory access instruction or alloca.
276    pub fn get_alignment(self) -> Result<u32, &'static str> {
277        if !self.is_a_alloca_inst() && !self.is_a_load_inst() && !self.is_a_store_inst() {
278            return Err("Value is not an alloca, load or store.");
279        }
280        Ok(unsafe { LLVMGetAlignment(self.as_value_ref()) })
281    }
282
283    // SubTypes: Only apply to memory access and alloca instructions
284    /// Sets alignment on a memory access instruction or alloca.
285    pub fn set_alignment(self, alignment: u32) -> Result<(), &'static str> {
286        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
287        {
288            if alignment == 0 {
289                return Err("Alignment cannot be 0");
290            }
291        }
292        //The alignment = 0 check above covers LLVM >= 11, the != 0 check here keeps older versions compatible
293        if !alignment.is_power_of_two() && alignment != 0 {
294            return Err("Alignment is not a power of 2!");
295        }
296        if !self.is_a_alloca_inst() && !self.is_a_load_inst() && !self.is_a_store_inst() {
297            return Err("Value is not an alloca, load or store.");
298        }
299        unsafe { LLVMSetAlignment(self.as_value_ref(), alignment) };
300        Ok(())
301    }
302
303    // SubTypes: Only apply to memory access instructions
304    /// Returns atomic ordering on a memory access instruction.
305    pub fn get_atomic_ordering(self) -> Result<AtomicOrdering, &'static str> {
306        if !self.is_a_load_inst() && !self.is_a_store_inst() {
307            return Err("Value is not a load or store.");
308        }
309        Ok(unsafe { LLVMGetOrdering(self.as_value_ref()) }.into())
310    }
311
312    // SubTypes: Only apply to memory access instructions
313    /// Sets atomic ordering on a memory access instruction.
314    pub fn set_atomic_ordering(self, ordering: AtomicOrdering) -> Result<(), &'static str> {
315        // Although fence and atomicrmw both have an ordering, the LLVM C API
316        // does not support them. The cmpxchg instruction has two orderings and
317        // does not work with this API.
318        if !self.is_a_load_inst() && !self.is_a_store_inst() {
319            return Err("Value is not a load or store instruction.");
320        }
321        match ordering {
322            AtomicOrdering::Release if self.is_a_load_inst() => {
323                return Err("The release ordering is not valid on load instructions.")
324            },
325            AtomicOrdering::AcquireRelease => {
326                return Err("The acq_rel ordering is not valid on load or store instructions.")
327            },
328            AtomicOrdering::Acquire if self.is_a_store_inst() => {
329                return Err("The acquire ordering is not valid on store instructions.")
330            },
331            _ => {},
332        };
333        unsafe { LLVMSetOrdering(self.as_value_ref(), ordering.into()) };
334        Ok(())
335    }
336
337    /// Obtains the number of operands an `InstructionValue` has.
338    /// An operand is a `BasicValue` used in an IR instruction.
339    ///
340    /// The following example,
341    ///
342    /// ```no_run
343    /// use inkwell::AddressSpace;
344    /// use inkwell::context::Context;
345    ///
346    /// let context = Context::create();
347    /// let module = context.create_module("ivs");
348    /// let builder = context.create_builder();
349    /// let void_type = context.void_type();
350    /// let f32_type = context.f32_type();
351    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
352    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
353    ///
354    /// let function = module.add_function("take_f32_ptr", fn_type, None);
355    /// let basic_block = context.append_basic_block(function, "entry");
356    ///
357    /// builder.position_at_end(basic_block);
358    ///
359    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
360    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
361    /// let store_instruction = builder.build_store(arg1, f32_val);
362    /// let free_instruction = builder.build_free(arg1);
363    /// let return_instruction = builder.build_return(None);
364    ///
365    /// assert_eq!(store_instruction.get_num_operands(), 2);
366    /// assert_eq!(free_instruction.get_num_operands(), 2);
367    /// assert_eq!(return_instruction.get_num_operands(), 0);
368    /// ```
369    ///
370    /// will generate LLVM IR roughly like (varying slightly across LLVM versions):
371    ///
372    /// ```ir
373    /// ; ModuleID = 'ivs'
374    /// source_filename = "ivs"
375    ///
376    /// define void @take_f32_ptr(float* %0) {
377    /// entry:
378    ///   store float 0x400921FB60000000, float* %0
379    ///   %1 = bitcast float* %0 to i8*
380    ///   tail call void @free(i8* %1)
381    ///   ret void
382    /// }
383    ///
384    /// declare void @free(i8*)
385    /// ```
386    ///
387    /// which makes the number of instruction operands clear:
388    /// 1) Store has two: a const float and a variable float pointer %0
389    /// 2) Bitcast has one: a variable float pointer %0
390    /// 3) Function call has two: i8 pointer %1 argument, and the free function itself
391    /// 4) Void return has zero: void is not a value and does not count as an operand
392    /// even though the return instruction can take values.
393    pub fn get_num_operands(self) -> u32 {
394        unsafe { LLVMGetNumOperands(self.as_value_ref()) as u32 }
395    }
396
397    /// Obtains the operand an `InstructionValue` has at a given index if any.
398    /// An operand is a `BasicValue` used in an IR instruction.
399    ///
400    /// The following example,
401    ///
402    /// ```no_run
403    /// use inkwell::AddressSpace;
404    /// use inkwell::context::Context;
405    ///
406    /// let context = Context::create();
407    /// let module = context.create_module("ivs");
408    /// let builder = context.create_builder();
409    /// let void_type = context.void_type();
410    /// let f32_type = context.f32_type();
411    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
412    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
413    ///
414    /// let function = module.add_function("take_f32_ptr", fn_type, None);
415    /// let basic_block = context.append_basic_block(function, "entry");
416    ///
417    /// builder.position_at_end(basic_block);
418    ///
419    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
420    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
421    /// let store_instruction = builder.build_store(arg1, f32_val);
422    /// let free_instruction = builder.build_free(arg1);
423    /// let return_instruction = builder.build_return(None);
424    ///
425    /// assert!(store_instruction.get_operand(0).is_some());
426    /// assert!(store_instruction.get_operand(1).is_some());
427    /// assert!(store_instruction.get_operand(2).is_none());
428    /// assert!(free_instruction.get_operand(0).is_some());
429    /// assert!(free_instruction.get_operand(1).is_some());
430    /// assert!(free_instruction.get_operand(2).is_none());
431    /// assert!(return_instruction.get_operand(0).is_none());
432    /// assert!(return_instruction.get_operand(1).is_none());
433    /// ```
434    ///
435    /// will generate LLVM IR roughly like (varying slightly across LLVM versions):
436    ///
437    /// ```ir
438    /// ; ModuleID = 'ivs'
439    /// source_filename = "ivs"
440    ///
441    /// define void @take_f32_ptr(float* %0) {
442    /// entry:
443    ///   store float 0x400921FB60000000, float* %0
444    ///   %1 = bitcast float* %0 to i8*
445    ///   tail call void @free(i8* %1)
446    ///   ret void
447    /// }
448    ///
449    /// declare void @free(i8*)
450    /// ```
451    ///
452    /// which makes the instruction operands clear:
453    /// 1) Store has two: a const float and a variable float pointer %0
454    /// 2) Bitcast has one: a variable float pointer %0
455    /// 3) Function call has two: i8 pointer %1 argument, and the free function itself
456    /// 4) Void return has zero: void is not a value and does not count as an operand
457    /// even though the return instruction can take values.
458    pub fn get_operand(self, index: u32) -> Option<Either<BasicValueEnum<'ctx>, BasicBlock<'ctx>>> {
459        let num_operands = self.get_num_operands();
460
461        if index >= num_operands {
462            return None;
463        }
464
465        let operand = unsafe { LLVMGetOperand(self.as_value_ref(), index) };
466
467        if operand.is_null() {
468            return None;
469        }
470
471        let is_basic_block = unsafe { !LLVMIsABasicBlock(operand).is_null() };
472
473        if is_basic_block {
474            let bb = unsafe { BasicBlock::new(LLVMValueAsBasicBlock(operand)) };
475
476            Some(Right(bb.expect("BasicBlock should always be valid")))
477        } else {
478            Some(Left(unsafe { BasicValueEnum::new(operand) }))
479        }
480    }
481
482    /// Sets the operand an `InstructionValue` has at a given index if possible.
483    /// An operand is a `BasicValue` used in an IR instruction.
484    ///
485    /// ```no_run
486    /// use inkwell::AddressSpace;
487    /// use inkwell::context::Context;
488    ///
489    /// let context = Context::create();
490    /// let module = context.create_module("ivs");
491    /// let builder = context.create_builder();
492    /// let void_type = context.void_type();
493    /// let f32_type = context.f32_type();
494    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
495    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
496    ///
497    /// let function = module.add_function("take_f32_ptr", fn_type, None);
498    /// let basic_block = context.append_basic_block(function, "entry");
499    ///
500    /// builder.position_at_end(basic_block);
501    ///
502    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
503    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
504    /// let store_instruction = builder.build_store(arg1, f32_val);
505    /// let free_instruction = builder.build_free(arg1);
506    /// let return_instruction = builder.build_return(None);
507    ///
508    /// // This will produce invalid IR:
509    /// free_instruction.set_operand(0, f32_val);
510    ///
511    /// assert_eq!(free_instruction.get_operand(0).unwrap().left().unwrap(), f32_val);
512    /// ```
513    pub fn set_operand<BV: BasicValue<'ctx>>(self, index: u32, val: BV) -> bool {
514        let num_operands = self.get_num_operands();
515
516        if index >= num_operands {
517            return false;
518        }
519
520        unsafe { LLVMSetOperand(self.as_value_ref(), index, val.as_value_ref()) }
521
522        true
523    }
524
525    /// Gets the use of an operand(`BasicValue`), if any.
526    ///
527    /// ```no_run
528    /// use inkwell::AddressSpace;
529    /// use inkwell::context::Context;
530    /// use inkwell::values::BasicValue;
531    ///
532    /// let context = Context::create();
533    /// let module = context.create_module("ivs");
534    /// let builder = context.create_builder();
535    /// let void_type = context.void_type();
536    /// let f32_type = context.f32_type();
537    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
538    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
539    ///
540    /// let function = module.add_function("take_f32_ptr", fn_type, None);
541    /// let basic_block = context.append_basic_block(function, "entry");
542    ///
543    /// builder.position_at_end(basic_block);
544    ///
545    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
546    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
547    /// let store_instruction = builder.build_store(arg1, f32_val);
548    /// let free_instruction = builder.build_free(arg1);
549    /// let return_instruction = builder.build_return(None);
550    ///
551    /// assert_eq!(store_instruction.get_operand_use(1), arg1.get_first_use());
552    /// ```
553    pub fn get_operand_use(self, index: u32) -> Option<BasicValueUse<'ctx>> {
554        let num_operands = self.get_num_operands();
555
556        if index >= num_operands {
557            return None;
558        }
559
560        let use_ = unsafe { LLVMGetOperandUse(self.as_value_ref(), index) };
561
562        if use_.is_null() {
563            return None;
564        }
565
566        unsafe { Some(BasicValueUse::new(use_)) }
567    }
568
569    /// Gets the first use of an `InstructionValue` if any.
570    ///
571    /// The following example,
572    ///
573    /// ```no_run
574    /// use inkwell::AddressSpace;
575    /// use inkwell::context::Context;
576    /// use inkwell::values::BasicValue;
577    ///
578    /// let context = Context::create();
579    /// let module = context.create_module("ivs");
580    /// let builder = context.create_builder();
581    /// let void_type = context.void_type();
582    /// let f32_type = context.f32_type();
583    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
584    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
585    ///
586    /// let function = module.add_function("take_f32_ptr", fn_type, None);
587    /// let basic_block = context.append_basic_block(function, "entry");
588    ///
589    /// builder.position_at_end(basic_block);
590    ///
591    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
592    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
593    /// let store_instruction = builder.build_store(arg1, f32_val);
594    /// let free_instruction = builder.build_free(arg1);
595    /// let return_instruction = builder.build_return(None);
596    ///
597    /// assert!(arg1.get_first_use().is_some());
598    /// ```
599    pub fn get_first_use(self) -> Option<BasicValueUse<'ctx>> {
600        self.instruction_value.get_first_use()
601    }
602
603    /// Gets the predicate of an `ICmp` `InstructionValue`.
604    /// For instance, in the LLVM instruction
605    /// `%3 = icmp slt i32 %0, %1`
606    /// this gives the `slt`.
607    ///
608    /// If the instruction is not an `ICmp`, this returns None.
609    pub fn get_icmp_predicate(self) -> Option<IntPredicate> {
610        // REVIEW: this call to get_opcode() can be inefficient;
611        // what happens if we don't perform this check, and just call
612        // LLVMGetICmpPredicate() regardless?
613        if self.get_opcode() == InstructionOpcode::ICmp {
614            let pred = unsafe { LLVMGetICmpPredicate(self.as_value_ref()) };
615            Some(IntPredicate::new(pred))
616        } else {
617            None
618        }
619    }
620
621    /// Gets the predicate of an `FCmp` `InstructionValue`.
622    /// For instance, in the LLVM instruction
623    /// `%3 = fcmp olt float %0, %1`
624    /// this gives the `olt`.
625    ///
626    /// If the instruction is not an `FCmp`, this returns None.
627    pub fn get_fcmp_predicate(self) -> Option<FloatPredicate> {
628        // REVIEW: this call to get_opcode() can be inefficient;
629        // what happens if we don't perform this check, and just call
630        // LLVMGetFCmpPredicate() regardless?
631        if self.get_opcode() == InstructionOpcode::FCmp {
632            let pred = unsafe { LLVMGetFCmpPredicate(self.as_value_ref()) };
633            Some(FloatPredicate::new(pred))
634        } else {
635            None
636        }
637    }
638
639    /// Determines whether or not this `Instruction` has any associated metadata.
640    pub fn has_metadata(self) -> bool {
641        unsafe { LLVMHasMetadata(self.instruction_value.value) == 1 }
642    }
643
644    /// Gets the `MetadataValue` associated with this `Instruction` at a specific
645    /// `kind_id`.
646    pub fn get_metadata(self, kind_id: u32) -> Option<MetadataValue<'ctx>> {
647        let metadata_value = unsafe { LLVMGetMetadata(self.instruction_value.value, kind_id) };
648
649        if metadata_value.is_null() {
650            return None;
651        }
652
653        unsafe { Some(MetadataValue::new(metadata_value)) }
654    }
655
656    /// Determines whether or not this `Instruction` has any associated metadata
657    /// `kind_id`.
658    pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) -> Result<(), &'static str> {
659        if !metadata.is_node() {
660            return Err("metadata is expected to be a node.");
661        }
662
663        unsafe {
664            LLVMSetMetadata(self.instruction_value.value, kind_id, metadata.as_value_ref());
665        }
666
667        Ok(())
668    }
669}
670
671impl Clone for InstructionValue<'_> {
672    /// Creates a clone of this `InstructionValue`, and returns it.
673    /// The clone will have no parent, and no name.
674    fn clone(&self) -> Self {
675        unsafe { InstructionValue::new(LLVMInstructionClone(self.as_value_ref())) }
676    }
677}
678
679unsafe impl AsValueRef for InstructionValue<'_> {
680    fn as_value_ref(&self) -> LLVMValueRef {
681        self.instruction_value.value
682    }
683}
684
685impl Display for InstructionValue<'_> {
686    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
687        write!(f, "{}", self.print_to_string())
688    }
689}