// =======================================================
// LoadInst
// =======================================================
///|
pub(all) enum AtomicOrdering {
NotAtomic
Unordered
Monotonic
Acquire
Release
AcquireRelease
SequentiallyConsistent
} derive(Hash, Eq)
///|
pub impl Show for AtomicOrdering with output(self, logger) {
let str = match self {
NotAtomic => ""
Unordered => "unordered"
Monotonic => "monotonic"
Acquire => "acquire"
Release => "release"
AcquireRelease => "acquire_release"
SequentiallyConsistent => "sequentially_consistent"
}
logger.write_string(str)
}
///|
/// LoadInst is an instruction that loads a value from a pointer.
///
/// **Note**:
///
/// Use `IRBuilder::createLoad` to create a `LoadInst`.
///
/// ```mbt check
/// test {
/// let ctx = Context::new()
/// let mod = ctx.addModule("demo")
/// let builder = ctx.createBuilder()
/// let ptr_ty = ctx.getPtrTy()
/// let i32_ty = ctx.getInt32Ty()
/// let fty = ctx.getFunctionType(i32_ty, [ptr_ty])
/// let fval = mod.addFunction(fty, "load_an_integer")
/// let bb = fval.addBasicBlock(name="entry")
/// builder.setInsertPoint(bb)
/// let ptr = fval.getArg(0).unwrap()
/// ptr.setName("arg0")
/// let val = builder.createLoad(i32_ty, ptr, name="val")
/// let _ = builder.createRet(val)
/// inspect(val, content=" %val = load i32, ptr %arg0, align 4")
/// }
/// ```
pub(all) struct LoadInst {
// --- ValueBase ---
// Unique identifier
uid : UInt64
// Type of the value
vty : &Type
// Users of this value
users : Array[&User]
// Name of the value
mut name : String?
// --- UserBase ---
// Pointer which this instruction loads from.
ptr : &Value
parent : Function
// --- InstBase ---
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
// --- LoadInst ---
isVolatile : Bool
atomicOrdering : AtomicOrdering
align : Align
}
///|
fn LoadInst::new(
load_ty : &Type,
ptr : &Value,
isVolatile : Bool,
atomicOrdering : AtomicOrdering,
parent : Function,
name~ : String?,
) -> LoadInst {
let vty = load_ty
let bb : Ref[BasicBlock?] = Ref::new(None)
let prev : Ref[&Instruction?] = Ref::new(None)
let next : Ref[&Instruction?] = Ref::new(None)
let align = parent.getDataLayout().getAlignment(load_ty)
let uid = valueUIDAssigner.assign()
let inst = LoadInst::{
uid,
vty,
name,
users: [],
ptr,
parent,
bb,
prev,
next,
isVolatile,
atomicOrdering,
align,
}
ptr.addUser(inst)
inst
}
///|
pub impl Value for LoadInst with asValueEnum(self) {
LoadInst(self)
}
///|
pub impl Value for LoadInst with getValueBase(self) {
ValueBase::{ uid: self.uid, vty: self.vty, users: self.users }
}
///|
/// Get simple representation of the value.
///
/// ```mbt check
/// test {
/// let ctx = Context::new()
/// let mod = ctx.addModule("demo")
/// let builder = ctx.createBuilder()
/// let ptr_ty = ctx.getPtrTy()
/// let i32_ty = ctx.getInt32Ty()
/// let fty = ctx.getFunctionType(i32_ty, [ptr_ty])
/// let fval = mod.addFunction(fty, "load_an_integer")
/// let bb = fval.addBasicBlock(name="entry")
/// builder.setInsertPoint(bb)
/// let ptr = fval.getArg(0).unwrap()
/// let val = builder.createLoad(i32_ty, ptr)
/// inspect(val.getValueRepr(), content="%1")
/// val.setName("val")
/// inspect(val.getValueRepr(), content="%val")
/// }
/// ```
pub impl Value for LoadInst with getValueRepr(self) {
match self.getNameOrSlot() {
Some(Left(name)) => "%\{name}"
Some(Right(slot)) => "%\{slot}"
None => ""
}
}
///|
/// Get the name of the instruction.
///
/// **Note**:
///
/// If the instruction has no name, return `None`.
///
/// ```mbt check
/// test {
/// let ctx = Context::new()
/// let mod = ctx.addModule("demo")
/// let builder = ctx.createBuilder()
/// let ptr_ty = ctx.getPtrTy()
/// let i32_ty = ctx.getInt32Ty()
/// let fty = ctx.getFunctionType(i32_ty, [ptr_ty])
/// let fval = mod.addFunction(fty, "load_an_integer")
/// let bb = fval.addBasicBlock(name="entry")
/// builder.setInsertPoint(bb)
/// let ptr = fval.getArg(0).unwrap()
/// let val = builder.createLoad(i32_ty, ptr)
/// inspect(val.getName(), content="None")
/// val.setName("val")
/// inspect(val.getName(), content="Some(\"val\")")
/// }
/// ```
pub impl Value for LoadInst with getName(self) {
self.name
}
///|
/// Set the name of the instruction.
///
/// **Note**:
///
/// If the name has already been used in the parent function,
/// it will raise Error.
///
/// ```mbt check
/// test {
/// let ctx = Context::new()
/// let mod = ctx.addModule("demo")
/// let builder = ctx.createBuilder()
/// let ptr_ty = ctx.getPtrTy()
/// let i32_ty = ctx.getInt32Ty()
/// let fty = ctx.getFunctionType(i32_ty, [ptr_ty])
/// let fval = mod.addFunction(fty, "load_an_integer")
/// let bb = fval.addBasicBlock(name="entry")
/// builder.setInsertPoint(bb)
/// let ptr = fval.getArg(0).unwrap()
/// let val = builder.createLoad(i32_ty, ptr)
/// inspect(val.getName(), content="None")
/// val.setName("val")
/// inspect(val.getName(), content="Some(\"val\")")
/// }
/// ```
pub impl Value for LoadInst with setName(self, name) {
match self.getParent().setSymbol(name, self) {
EmptyName => {
let msg = "Misuse `LoadInst::setName`: name cannot be empty."
raise LLVMValueError(msg)
}
InvalidName => {
let msg =
$|Misuse `LoadInst::setName`:
$|name '\{name}' contains illegal characters,
$|only alphanumeric characters and underscores are allowed
raise LLVMValueError(msg)
}
DuplicateName(existed) => {
let msg =
$|Misuse `LoadInst::setName`:
$|name '\{name}' already exists in the parent function,
$|it is used by:
$|\{existed}"
raise LLVMValueError(msg)
}
Success => self.name = Some(name)
}
}
///|
/// Remove the name of the instruction.
pub impl Value for LoadInst with removeName(self) {
match self.name {
None => ()
Some(name) => {
self.getParent().removeSymbol(name)
self.name = None
}
}
}
///|
pub impl Value for LoadInst with getNameOrSlot(self) {
match self.name {
Some(name) => Some(Left(name))
None =>
match self.getParent().getSlot(self) {
Some(slot) => Some(Right(slot))
None => None
}
}
}
///|
pub impl User for LoadInst with asUserEnum(self) {
LoadInst(self)
}
///|
pub impl User for LoadInst with getUserBase(self) {
UserBase::{ operands: [self.ptr] }
}
///|
pub impl Instruction for LoadInst with getInstBase(self) {
InstBase::{ bb: self.bb, prev: self.prev, next: self.next }
}
///|
pub impl Instruction for LoadInst with asInstEnum(self) {
LoadInst(self)
}
///|
pub impl Instruction for LoadInst with getParent(self) {
self.parent
}
///|
pub impl UnaryInst for LoadInst with asUnaryInstEnum(self) {
LoadInst(self)
}
///|
pub impl Show for LoadInst with output(self, logger) {
let align = self.align
let repr = self.getValueRepr()
let ptr_repr = self.ptr.getValueRepr()
let load_ty = self.getType()
let str = match (self.isVolatile, self.atomicOrdering) {
(true, _) =>
" \{repr} = load volatile \{load_ty}, ptr \{ptr_repr}, \{align}"
(false, NotAtomic) =>
" \{repr} = load \{load_ty}, ptr \{ptr_repr}, \{align}"
(false, _) =>
" \{repr} = load atomic \{load_ty}, ptr \{ptr_repr} \{self.atomicOrdering}, \{align}"
}
logger.write_string(str)
}