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}