use nvbit_sys::{bindings, nvbit};
use std::marker::PhantomData;
use std::{ffi, fmt, pin::Pin};
#[repr(transparent)]
#[derive(Debug)]
#[allow(dead_code)]
pub struct Operand<'a> {
ptr: *const nvbit::operand_t,
instr: PhantomData<Instruction<'a>>,
}
impl<'a> Operand<'a> {
#[inline]
#[must_use]
pub fn into_owned(&self) -> nvbit::operand_t {
unsafe { *self.ptr }
}
}
#[derive(Debug)]
pub enum MemorySpace {
None,
Local,
Generic,
Global,
Shared,
Constant,
GlobalToShared,
Surface,
Texture,
}
impl From<bindings::InstrType_MemorySpace> for MemorySpace {
#[inline]
#[must_use]
fn from(mem_space: bindings::InstrType_MemorySpace) -> Self {
use bindings::InstrType_MemorySpace as MS;
match mem_space {
MS::NONE => MemorySpace::None,
MS::LOCAL => MemorySpace::Local,
MS::GENERIC => MemorySpace::Generic,
MS::GLOBAL => MemorySpace::Global,
MS::SHARED => MemorySpace::Shared,
MS::CONSTANT => MemorySpace::Constant,
MS::GLOBAL_TO_SHARED => MemorySpace::GlobalToShared,
MS::SURFACE => MemorySpace::Surface,
MS::TEXTURE => MemorySpace::Texture,
}
}
}
#[derive(Debug, Clone)]
pub struct Predicate {
pub num: i32,
pub is_neg: bool,
pub is_uniform: bool,
}
#[repr(transparent)]
#[derive(PartialEq, Eq, Hash)]
pub struct Instruction<'a> {
inner: *mut nvbit::Instr,
func: PhantomData<super::Function<'a>>,
}
impl<'a> fmt::Debug for Instruction<'a> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Instruction")
.finish()
}
}
impl<'a> AsMut<nvbit::Instr> for Instruction<'a> {
#[inline]
#[must_use]
fn as_mut(&mut self) -> &mut nvbit::Instr {
unsafe { &mut *self.inner as &mut nvbit::Instr }
}
}
impl<'a> AsRef<nvbit::Instr> for Instruction<'a> {
#[inline]
#[must_use]
fn as_ref(&self) -> &nvbit::Instr {
unsafe { &*self.inner as &nvbit::Instr }
}
}
impl<'a> Instruction<'a> {
#[inline]
#[must_use]
pub fn new(instr: *mut nvbit::Instr) -> Self {
Self {
inner: instr,
func: PhantomData,
}
}
#[inline]
#[must_use]
pub fn as_ptr(&self) -> *const nvbit::Instr {
self.inner as *const _
}
#[inline]
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut nvbit::Instr {
self.inner
}
#[inline]
#[must_use]
pub fn pin_mut(&mut self) -> Pin<&mut nvbit::Instr> {
unsafe { Pin::new_unchecked(self.as_mut()) }
}
#[inline]
#[must_use]
pub fn sass(&mut self) -> Option<&'a str> {
let sass = self.pin_mut().getSass();
if sass.is_null() {
None
} else {
unsafe { ffi::CStr::from_ptr(sass) }.to_str().ok()
}
}
#[inline]
#[must_use]
pub fn offset(&mut self) -> u32 {
self.pin_mut().getOffset()
}
#[inline]
#[must_use]
pub fn idx(&mut self) -> u32 {
self.pin_mut().getIdx()
}
#[inline]
#[must_use]
pub fn has_pred(&mut self) -> Option<Predicate> {
if self.pin_mut().hasPred() {
Some(Predicate {
num: self.pin_mut().getPredNum(),
is_neg: self.pin_mut().isPredNeg(),
is_uniform: self.pin_mut().isPredUniform(),
})
} else {
None
}
}
#[inline]
#[must_use]
pub fn opcode(&mut self) -> Option<&'a str> {
let opcode = self.pin_mut().getOpcode();
if opcode.is_null() {
None
} else {
unsafe { ffi::CStr::from_ptr(opcode) }.to_str().ok()
}
}
#[inline]
#[must_use]
pub fn opcode_short(&mut self) -> Option<&'a str> {
let opcode = self.pin_mut().getOpcodeShort();
if opcode.is_null() {
None
} else {
unsafe { ffi::CStr::from_ptr(opcode) }.to_str().ok()
}
}
#[inline]
#[must_use]
pub fn memory_space(&mut self) -> MemorySpace {
self.pin_mut().getMemorySpace().into()
}
#[inline]
#[must_use]
pub fn is_load(&mut self) -> bool {
self.pin_mut().isLoad()
}
#[inline]
#[must_use]
pub fn is_store(&mut self) -> bool {
self.pin_mut().isStore()
}
#[inline]
#[must_use]
pub fn is_extended(&mut self) -> bool {
self.pin_mut().isExtended()
}
#[inline]
#[must_use]
pub fn size(&mut self) -> usize {
self.pin_mut().getSize().unsigned_abs() as usize
}
#[inline]
#[must_use]
pub fn num_operands(&mut self) -> usize {
self.pin_mut().getNumOperands().unsigned_abs() as usize
}
#[inline]
#[must_use]
pub fn operand(&mut self, idx: usize) -> Option<Operand<'a>> {
if idx >= self.num_operands() {
return None;
}
let idx: i32 = if let Ok(idx) = idx.try_into() {
idx
} else {
return None;
};
let ptr = self.pin_mut().getOperand(idx);
if ptr.is_null() {
None
} else {
Some(Operand {
ptr,
instr: PhantomData,
})
}
}
#[inline]
pub fn print_decoded(&mut self) {
self.pin_mut().printDecoded();
}
#[inline]
pub fn print_with_prefix(&mut self, prefix: &str) {
let prefix = ffi::CString::new(prefix).unwrap_or_default().as_ptr();
unsafe { self.pin_mut().print(prefix) };
}
}
#[derive(Debug, Clone, Copy)]
pub enum InsertionPoint {
Before,
After,
}
impl From<InsertionPoint> for bindings::ipoint_t {
#[inline]
#[must_use]
fn from(point: InsertionPoint) -> bindings::ipoint_t {
use bindings::ipoint_t as IP;
match point {
InsertionPoint::Before => IP::IPOINT_BEFORE,
InsertionPoint::After => IP::IPOINT_AFTER,
}
}
}
impl From<bindings::ipoint_t> for InsertionPoint {
#[inline]
#[must_use]
fn from(point: bindings::ipoint_t) -> Self {
use bindings::ipoint_t as IP;
match point {
IP::IPOINT_BEFORE => Self::Before,
IP::IPOINT_AFTER => Self::After,
}
}
}
impl<'a> Instruction<'a> {
#[inline]
pub fn insert_call(&mut self, dev_func_name: impl AsRef<str>, point: InsertionPoint) {
let func_name = ffi::CString::new(dev_func_name.as_ref()).unwrap();
unsafe {
bindings::nvbit_insert_call(self.as_ptr().cast(), func_name.as_ptr(), point.into());
}
}
#[inline]
pub fn add_call_arg_guard_pred_val(&mut self) {
unsafe { bindings::nvbit_add_call_arg_guard_pred_val(self.as_ptr().cast(), false) };
}
#[inline]
pub fn add_call_arg_pred_val_at(&mut self, pred_num: i32) {
unsafe { bindings::nvbit_add_call_arg_pred_val_at(self.as_ptr().cast(), pred_num, false) };
}
#[inline]
pub fn add_call_arg_upred_val_at(&mut self, upred_num: i32) {
unsafe {
bindings::nvbit_add_call_arg_upred_val_at(self.as_ptr().cast(), upred_num, false);
};
}
#[inline]
pub fn add_call_arg_pred_reg(&mut self) {
unsafe {
bindings::nvbit_add_call_arg_pred_reg(self.as_ptr().cast(), false);
};
}
#[inline]
pub fn add_call_arg_upred_reg(&mut self) {
unsafe {
bindings::nvbit_add_call_arg_upred_reg(self.as_ptr().cast(), false);
};
}
#[inline]
pub fn add_call_arg_const_val32(&mut self, val: u32) {
unsafe { bindings::nvbit_add_call_arg_const_val32(self.as_ptr().cast(), val, false) };
}
#[inline]
pub fn add_call_arg_const_val64(&mut self, val: u64) {
unsafe { bindings::nvbit_add_call_arg_const_val64(self.as_ptr().cast(), val, false) };
}
#[inline]
pub fn add_call_arg_reg_val(&mut self, reg_num: i32) {
unsafe { bindings::nvbit_add_call_arg_reg_val(self.as_ptr().cast(), reg_num, false) };
}
#[inline]
pub fn add_call_arg_ureg_val(&mut self, reg_num: i32) {
unsafe { bindings::nvbit_add_call_arg_ureg_val(self.as_ptr().cast(), reg_num, false) };
}
#[inline]
pub fn add_call_arg_launch_val32(&mut self, offset: i32) {
unsafe { bindings::nvbit_add_call_arg_launch_val32(self.as_ptr().cast(), offset, false) };
}
#[inline]
pub fn add_call_arg_launch_val64(&mut self, offset: i32) {
unsafe { bindings::nvbit_add_call_arg_launch_val64(self.as_ptr().cast(), offset, false) };
}
#[inline]
pub fn add_call_arg_cbank_val(&mut self, bank_id: i32, bank_offset: i32) {
unsafe {
bindings::nvbit_add_call_arg_cbank_val(
self.as_ptr().cast(),
bank_id,
bank_offset,
false,
);
};
}
#[inline]
pub fn add_call_arg_mref_addr64(&mut self, id: i32) {
unsafe { bindings::nvbit_add_call_arg_mref_addr64(self.as_ptr().cast(), id, false) };
}
#[inline]
pub fn remove_orig(&mut self) {
unsafe { bindings::nvbit_remove_orig(self.as_ptr().cast()) };
}
}