Skip to content

Commit bba370c

Browse files
committed
Allow obtaining BasicBlock from get_operand
1 parent 87a3dc2 commit bba370c

File tree

3 files changed

+48
-11
lines changed

3 files changed

+48
-11
lines changed

src/values/basic_value_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ impl BasicValueUse {
144144
/// let free_instruction = builder.build_free(arg1);
145145
/// let return_instruction = builder.build_return(None);
146146
///
147-
/// let free_operand0 = free_instruction.get_operand(0).unwrap();
147+
/// let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap();
148148
/// let free_operand0_instruction = free_operand0.as_instruction_value().unwrap();
149149
/// let bitcast_use_value = free_operand0_instruction
150150
/// .get_first_use()

src/values/instruction_value.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use llvm_sys::core::{LLVMGetInstructionOpcode, LLVMIsTailCall, LLVMGetPreviousInstruction, LLVMGetNextInstruction, LLVMGetInstructionParent, LLVMInstructionEraseFromParent, LLVMInstructionClone, LLVMSetVolatile, LLVMGetVolatile, LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMSetOperand};
1+
use either::{Either, Either::{Left, Right}};
2+
use llvm_sys::core::{LLVMGetInstructionOpcode, LLVMIsTailCall, LLVMGetPreviousInstruction, LLVMGetNextInstruction, LLVMGetInstructionParent, LLVMInstructionEraseFromParent, LLVMInstructionClone, LLVMSetVolatile, LLVMGetVolatile, LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMSetOperand, LLVMValueAsBasicBlock, LLVMIsABasicBlock};
23
#[llvm_versions(3.9 => latest)]
34
use llvm_sys::core::LLVMInstructionRemoveFromParent;
45
use llvm_sys::LLVMOpcode;
@@ -464,7 +465,7 @@ impl InstructionValue {
464465
/// 3) Function call has two: i8 pointer %1 argument, and the free function itself
465466
/// 4) Void return has zero: void is not a value and does not count as an operand
466467
/// even though the return instruction can take values.
467-
pub fn get_operand(&self, index: u32) -> Option<BasicValueEnum> {
468+
pub fn get_operand(&self, index: u32) -> Option<Either<BasicValueEnum, BasicBlock>> {
468469
let num_operands = self.get_num_operands();
469470

470471
if index >= num_operands {
@@ -479,7 +480,19 @@ impl InstructionValue {
479480
return None;
480481
}
481482

482-
Some(BasicValueEnum::new(operand))
483+
let is_basic_block = unsafe {
484+
!LLVMIsABasicBlock(operand).is_null()
485+
};
486+
487+
if is_basic_block {
488+
let operand = unsafe {
489+
LLVMValueAsBasicBlock(operand)
490+
};
491+
492+
Some(Right(BasicBlock::new(operand).expect("BasicBlock should be valid")))
493+
} else {
494+
Some(Left(BasicValueEnum::new(operand)))
495+
}
483496
}
484497

485498
/// Sets the operand an `InstructionValue` has at a given index if possible.
@@ -511,7 +524,7 @@ impl InstructionValue {
511524
/// // This will produce invalid IR:
512525
/// free_instruction.set_operand(0, f32_val);
513526
///
514-
/// assert_eq!(free_instruction.get_operand(0).unwrap(), f32_val);
527+
/// assert_eq!(free_instruction.get_operand(0).unwrap().left().unwrap(), f32_val);
515528
/// ```
516529
pub fn set_operand<BV: BasicValue>(&self, index: u32, val: BV) -> bool {
517530
let num_operands = self.get_num_operands();

tests/all/test_instruction_values.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,20 @@ fn test_operands() {
3838
let store_operand0 = store_instruction.get_operand(0).unwrap();
3939
let store_operand1 = store_instruction.get_operand(1).unwrap();
4040

41-
assert_eq!(store_operand0, f32_val); // f32 const
42-
assert_eq!(store_operand1, arg1); // f32* arg1
41+
assert_eq!(store_operand0.left().unwrap(), f32_val); // f32 const
42+
assert_eq!(store_operand1.left().unwrap(), arg1); // f32* arg1
4343
assert!(store_instruction.get_operand(2).is_none());
4444
assert!(store_instruction.get_operand(3).is_none());
4545
assert!(store_instruction.get_operand(4).is_none());
4646

47-
let free_operand0 = free_instruction.get_operand(0).unwrap();
48-
let free_operand1 = free_instruction.get_operand(1).unwrap();
47+
let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap();
48+
let free_operand1 = free_instruction.get_operand(1).unwrap().left().unwrap();
4949
let free_operand0_instruction = free_operand0.as_instruction_value().unwrap();
5050

5151
assert!(free_operand0.is_pointer_value()); // (implictly casted) i8* arg1
5252
assert!(free_operand1.is_pointer_value()); // Free function ptr
5353
assert_eq!(free_operand0_instruction.get_opcode(), BitCast);
54-
assert_eq!(free_operand0_instruction.get_operand(0).unwrap(), arg1);
54+
assert_eq!(free_operand0_instruction.get_operand(0).unwrap().left().unwrap(), arg1);
5555
assert!(free_operand0_instruction.get_operand(1).is_none());
5656
assert!(free_operand0_instruction.get_operand(2).is_none());
5757
assert!(free_instruction.get_operand(2).is_none());
@@ -84,7 +84,7 @@ fn test_operands() {
8484
.get_first_use()
8585
.unwrap()
8686
.get_used_value();
87-
let free_call_param = free_instruction.get_operand(0).unwrap();
87+
let free_call_param = free_instruction.get_operand(0).unwrap().left().unwrap();
8888

8989
assert_eq!(bitcast_use_value, free_call_param);
9090

@@ -132,6 +132,30 @@ fn test_operands() {
132132
assert!(module.verify().is_ok());
133133
}
134134

135+
#[test]
136+
fn test_basic_block_operand() {
137+
let context = Context::create();
138+
let module = context.create_module("ivs");
139+
let builder = context.create_builder();
140+
let void_type = context.void_type();
141+
let fn_type = void_type.fn_type(&[], false);
142+
let function = module.add_function("bb_op", fn_type, None);
143+
let basic_block = context.append_basic_block(&function, "entry");
144+
let basic_block2 = context.append_basic_block(&function, "exit");
145+
146+
builder.position_at_end(&basic_block);
147+
148+
let branch_instruction = builder.build_unconditional_branch(&basic_block2);
149+
let bb_operand = branch_instruction.get_operand(0).unwrap().right().unwrap();
150+
151+
assert_eq!(bb_operand, basic_block2);
152+
153+
builder.position_at_end(&basic_block2);
154+
builder.build_return(None);
155+
156+
assert!(module.verify().is_ok());
157+
}
158+
135159
#[test]
136160
fn test_get_next_use() {
137161
let context = Context::create();

0 commit comments

Comments
 (0)