Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/values/basic_value_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use llvm_sys::prelude::LLVMUseRef;
use std::marker::PhantomData;

use crate::basic_block::BasicBlock;
use crate::values::{AnyValueEnum, BasicValueEnum};
use crate::values::{AnyValueEnum, BasicValueEnum, MetadataValue};

/// Either [BasicValueEnum] or [BasicBlock].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand All @@ -13,6 +13,8 @@ pub enum Operand<'ctx> {
Value(BasicValueEnum<'ctx>),
/// Represents a [BasicBlock].
Block(BasicBlock<'ctx>),
/// Represents a [MetadataValue].
Metadata(MetadataValue<'ctx>),
Comment thread
Yoric marked this conversation as resolved.
}

impl<'ctx> Operand<'ctx> {
Expand Down
4 changes: 2 additions & 2 deletions src/values/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl<'ctx> AnyValueEnum<'ctx> {
AnyValueEnum::InstructionValue(InstructionValue::new(value))
},
LLVMTypeKind::LLVMMetadataTypeKind => panic!("Metadata values are not supported as AnyValue's."),
_ => panic!("The given type is not supported."),
other => panic!("The given type is not supported: {:?}", other),
}
}

Expand Down Expand Up @@ -292,7 +292,7 @@ impl<'ctx> BasicValueEnum<'ctx> {
LLVMTypeKind::LLVMScalableVectorTypeKind => {
BasicValueEnum::ScalableVectorValue(ScalableVectorValue::new(value))
},
_ => unreachable!("The given type is not a basic type."),
other => panic!("The given type is not a basic type: {:?}", other),
}
}

Expand Down
27 changes: 17 additions & 10 deletions src/values/instruction_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ use llvm_sys::core::LLVMGetGEPSourceElementType;
use llvm_sys::core::{
LLVMGetAlignment, LLVMGetAllocatedType, LLVMGetFCmpPredicate, LLVMGetICmpPredicate, LLVMGetIndices,
LLVMGetInstructionOpcode, LLVMGetInstructionParent, LLVMGetMetadata, LLVMGetNextInstruction, LLVMGetNumIndices,
LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMGetPreviousInstruction, LLVMGetVolatile,
LLVMHasMetadata, LLVMInstructionClone, LLVMInstructionEraseFromParent, LLVMInstructionRemoveFromParent,
LLVMIsAAllocaInst, LLVMIsABasicBlock, LLVMIsAGetElementPtrInst, LLVMIsALoadInst, LLVMIsAStoreInst,
LLVMIsATerminatorInst, LLVMIsConditional, LLVMIsTailCall, LLVMSetAlignment, LLVMSetMetadata, LLVMSetOperand,
LLVMSetVolatile, LLVMValueAsBasicBlock,
LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMGetPreviousInstruction, LLVMGetTypeKind,
LLVMGetVolatile, LLVMHasMetadata, LLVMInstructionClone, LLVMInstructionEraseFromParent,
LLVMInstructionRemoveFromParent, LLVMIsAAllocaInst, LLVMIsABasicBlock, LLVMIsAGetElementPtrInst, LLVMIsALoadInst,
LLVMIsAStoreInst, LLVMIsATerminatorInst, LLVMIsAValueAsMetadata, LLVMIsConditional, LLVMIsTailCall,
LLVMSetAlignment, LLVMSetMetadata, LLVMSetOperand, LLVMSetVolatile, LLVMTypeOf, LLVMValueAsBasicBlock,
};
#[llvm_versions(10..)]
use llvm_sys::core::{LLVMGetAtomicRMWBinOp, LLVMIsAAtomicCmpXchgInst, LLVMIsAAtomicRMWInst};
use llvm_sys::core::{LLVMGetOrdering, LLVMSetOrdering};
use llvm_sys::prelude::LLVMValueRef;
use llvm_sys::LLVMOpcode;
use llvm_sys::{LLVMOpcode, LLVMTypeKind};

use std::{ffi::CStr, fmt, fmt::Display};

Expand Down Expand Up @@ -684,14 +684,21 @@ impl<'ctx> InstructionValue<'ctx> {
}

let is_basic_block = unsafe { !LLVMIsABasicBlock(operand).is_null() };

if is_basic_block {
let bb = unsafe { BasicBlock::new(LLVMValueAsBasicBlock(operand)) };

Some(Operand::Block(bb.expect("BasicBlock should always be valid")))
} else {
Some(Operand::Value(unsafe { BasicValueEnum::new(operand) }))
return Some(Operand::Block(bb.expect("BasicBlock should always be valid")));
}

if unsafe { LLVMGetTypeKind(LLVMTypeOf(operand)) == LLVMTypeKind::LLVMMetadataTypeKind } {
// We may be dealing with null metadata, which would break memory invariants.
if LLVMIsAValueAsMetadata(operand).is_null() {
return None;
}
return Some(Operand::Metadata(MetadataValue::new(operand)));
}

Some(Operand::Value(unsafe { BasicValueEnum::new(operand) }))
Comment thread
Yoric marked this conversation as resolved.
}

/// Get an instruction value operand iterator.
Expand Down
59 changes: 58 additions & 1 deletion tests/all/test_instruction_values.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use inkwell::context::Context;
use inkwell::debug_info::AsDIScope;
#[cfg(not(feature = "typed-pointers"))]
use inkwell::types::AnyType;
use inkwell::types::{AnyTypeEnum, BasicType};
use inkwell::values::{BasicValue, CallSiteValue, InstructionOpcode::*};
#[llvm_versions(10..)]
use inkwell::AtomicRMWBinOp;
use inkwell::{AddressSpace, AtomicOrdering, FloatPredicate, IntPredicate};
use inkwell::{debug_info, AddressSpace, AtomicOrdering, FloatPredicate, IntPredicate};

#[test]
#[ignore]
Expand Down Expand Up @@ -661,6 +662,62 @@ fn test_metadata_kinds() {
]);
}

#[test]
fn test_metadata_as_operand() {
// clang can introduce instructions such as
// call void @llvm.dbg.declare(metadata i32* %2, metadata !16, metadata !DIExpression()), !dbg !17
// we want to make sure that looking at the operands works.

let context = Context::create();
let module = context.create_module("testing");

let void_type = context.void_type();
let i32_type = context.i32_type();
let fn_type = void_type.fn_type(&[], false);
let function = module.add_function("fun", fn_type, None);
let block = context.append_basic_block(function, "block");

let (debug_info_builder, compile_unit) = module.create_debug_info_builder(
true,
debug_info::DWARFSourceLanguage::C,
"test.ll",
"/tmp",
"test",
false,
"",
0,
"split",
debug_info::DWARFEmissionKind::Full,
0,
false,
false,
"/",
"18.1",
);

let address_space = AddressSpace::default();
let debug_loc = debug_info_builder.create_debug_location(&context, 5, 32, compile_unit.as_debug_info_scope(), None);
#[allow(deprecated)]
let i32_ptr = i32_type.ptr_type(address_space).const_null();
let di_i32_type = debug_info_builder.create_basic_type("i32", 32, 0, 0).unwrap();
let var_info = debug_info_builder.create_auto_variable(
compile_unit.as_debug_info_scope(),
"var",
compile_unit.get_file(),
42,
di_i32_type.as_type(),
false,
0,
32,
);
let instruction = debug_info_builder.insert_declare_at_end(i32_ptr, Some(var_info), None, debug_loc, block);
assert_eq!(instruction.get_num_operands(), 4);
assert!(instruction.get_operand(0).is_some());
assert!(instruction.get_operand(1).is_none());
assert!(instruction.get_operand(2).is_none());
assert!(instruction.get_operand(3).is_some());
}

#[test]
fn test_find_instruction_with_name() {
use inkwell::context::Context;
Expand Down