// =======================================================
// FCmpInst
// =======================================================
///|
pub(all) enum FloatPredicate {
/// Always false (always folded)
FALSE
/// True if ordered and equal
OEQ
/// True if ordered and greater than
OGT
/// True if ordered and greater than or equal
OGE
/// True if ordered and less than
OLT
/// True if ordered and less than or equal
OLE
/// True if ordered and operands are unequal
ONE
/// True if ordered (no nans)
ORD
/// True if unordered: isnan(X) | isnan(Y)
UNO
/// True if unordered or equal
UEQ
/// True if unordered or greater than
UGT
/// True if unordered, greater than, or equal
UGE
/// True if unordered or less than
ULT
/// True if unordered, less than, or equal
ULE
/// True if unordered or not equal
UNE
/// Always true (always folded)
TRUE
}
///|
pub impl Show for FloatPredicate with output(self, logger) {
let s = match self {
FALSE => "fcmp false"
OEQ => "fcmp oeq"
OGT => "fcmp ogt"
OGE => "fcmp oge"
OLT => "fcmp olt"
OLE => "fcmp ole"
ONE => "fcmp one"
ORD => "fcmp ord"
UNO => "fcmp uno"
UEQ => "fcmp ueq"
UGT => "fcmp ugt"
UGE => "fcmp uge"
ULT => "fcmp ult"
ULE => "fcmp ule"
UNE => "fcmp une"
TRUE => "fcmp true"
}
logger.write_string(s)
}
///|
/// FCmpInst represents a floating-point comparison instruction that compares two floating-point values.
///
/// **Note**:
///
/// Use `IRBuilder::createFCmp` to create an `FCmpInst`.
///
/// ```mbt check
/// test {
/// let ctx = Context::new()
/// let mod = ctx.addModule("demo")
/// let builder = ctx.createBuilder()
/// let f32_ty = ctx.getFloatTy()
/// let fty = ctx.getFunctionType(f32_ty, [f32_ty, f32_ty])
/// let fval = mod.addFunction(fty, "fcmp_demo")
/// let bb = fval.addBasicBlock(name="entry")
/// let arg1 = fval.getArg(0).unwrap()
/// let arg2 = fval.getArg(1).unwrap()
/// builder.setInsertPoint(bb)
/// let oeq_cmp = builder.createFCmp(OEQ, arg1, arg2, name="oeq_cmp")
/// inspect(oeq_cmp, content=" %oeq_cmp = fcmp oeq float %0, %1")
/// assert_true(oeq_cmp.asValueEnum() is FCmpInst(_))
/// let ogt_cmp = builder.createFCmp(OGT, arg1, arg2, name="ogt_cmp")
/// inspect(ogt_cmp, content=" %ogt_cmp = fcmp ogt float %0, %1")
/// let olt_cmp = builder.createFCmp(OLT, arg1, arg2, name="olt_cmp")
/// inspect(olt_cmp, content=" %olt_cmp = fcmp olt float %0, %1")
/// let uno_cmp = builder.createFCmp(UNO, arg1, arg2, name="uno_cmp")
/// inspect(uno_cmp, content=" %uno_cmp = fcmp uno float %0, %1")
/// }
/// ```
pub struct FCmpInst {
uid : UInt64
vty : Int1Type
lhs : &Value
rhs : &Value
mut name : String?
parent : Function
users : Array[&User]
// --- InstBase ---
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
predicate : FloatPredicate
}
///|
fn FCmpInst::new(
predicate : FloatPredicate,
lhs : &Value,
rhs : &Value,
parent : Function,
name~ : String?,
) -> FCmpInst {
let (lhsTy, rhsTy) = (lhs.getType(), rhs.getType())
guard lhsTy == rhsTy
guard lhsTy.tryAsFPTypeEnum() is Some(_)
let uid = valueUIDAssigner.assign()
let bb : Ref[BasicBlock?] = Ref::new(None)
let prev : Ref[&Instruction?] = Ref::new(None)
let next : Ref[&Instruction?] = Ref::new(None)
let vty = parent.getContext().getInt1Ty()
let inst = FCmpInst::{
uid,
vty,
lhs,
rhs,
name,
parent,
users: [],
bb,
prev,
next,
predicate,
}
lhs.addUser(inst)
rhs.addUser(inst)
inst
}
///|
pub impl Value for FCmpInst 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 f32_ty = ctx.getFloatTy()
/// let fty = ctx.getFunctionType(f32_ty, [f32_ty, f32_ty])
/// let fval = mod.addFunction(fty, "fcmp_demo")
/// let bb = fval.addBasicBlock(name="entry")
/// let arg1 = fval.getArg(0).unwrap()
/// let arg2 = fval.getArg(1).unwrap()
/// builder.setInsertPoint(bb)
/// let oeq_cmp = builder.createFCmp(OEQ, arg1, arg2)
/// inspect(oeq_cmp.getValueRepr(), content="%2")
/// oeq_cmp.setName("oeq_cmp")
/// inspect(oeq_cmp.getValueRepr(), content="%oeq_cmp")
/// }
/// ```
pub impl Value for FCmpInst with getValueRepr(self) {
match self.getNameOrSlot() {
Some(Left(name)) => "%\{name}"
Some(Right(slot)) => "%\{slot}"
None => ""
}
}
///|
pub impl Value for FCmpInst with asValueEnum(self) {
FCmpInst(self)
}
///|
/// 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 f32_ty = ctx.getFloatTy()
/// let fty = ctx.getFunctionType(f32_ty, [f32_ty, f32_ty])
/// let fval = mod.addFunction(fty, "fcmp_demo")
/// let bb = fval.addBasicBlock(name="entry")
/// let arg1 = fval.getArg(0).unwrap()
/// let arg2 = fval.getArg(1).unwrap()
/// builder.setInsertPoint(bb)
/// let oeq_cmp = builder.createFCmp(OEQ, arg1, arg2)
/// inspect(oeq_cmp.getName(), content="None")
/// oeq_cmp.setName("oeq_cmp")
/// inspect(oeq_cmp.getName(), content="Some(\"oeq_cmp\")")
/// }
/// ```
pub impl Value for FCmpInst 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 f32_ty = ctx.getFloatTy()
/// let fty = ctx.getFunctionType(f32_ty, [f32_ty, f32_ty])
/// let fval = mod.addFunction(fty, "fcmp_demo")
/// let bb = fval.addBasicBlock(name="entry")
/// let arg1 = fval.getArg(0).unwrap()
/// let arg2 = fval.getArg(1).unwrap()
/// builder.setInsertPoint(bb)
/// let oeq_cmp = builder.createFCmp(OEQ, arg1, arg2)
/// inspect(oeq_cmp.getName(), content="None")
/// oeq_cmp.setName("oeq_cmp")
/// inspect(oeq_cmp.getName(), content="Some(\"oeq_cmp\")")
/// }
/// ```
pub impl Value for FCmpInst with setName(self, name) {
match self.getParent().setSymbol(name, self) {
EmptyName => {
let msg = "Misuse `FCmpInst::setName`: name cannot be empty."
raise LLVMValueError(msg)
}
InvalidName => {
let msg =
$|Misuse `FCmpInst::setName`:
$|name '\{name}' contains illegal characters,
$|only alphanumeric characters and underscores are allowed
raise LLVMValueError(msg)
}
DuplicateName(existed) => {
let msg =
$|Misuse `FCmpInst::setName`:
$|name '\{name}' already exists in the parent function,
$|it is used by:
$|\{existed}"
raise LLVMValueError(msg)
}
Success => self.name = Some(name)
}
}
///|
pub impl Value for FCmpInst with removeName(self) {
match self.name {
None => ()
Some(name) => {
self.getParent().symbols.remove(name)
self.name = None
}
}
}
///|
pub impl Value for FCmpInst 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 FCmpInst with asUserEnum(self) {
FCmpInst(self)
}
///|
pub impl User for FCmpInst with getUserBase(self) {
UserBase::{ operands: [self.lhs, self.rhs] }
}
///|
pub impl Instruction for FCmpInst with getInstBase(self) {
InstBase::{ bb: self.bb, prev: self.prev, next: self.next }
}
///|
pub impl Instruction for FCmpInst with asInstEnum(self) {
FCmpInst(self)
}
///|
pub impl Instruction for FCmpInst with getParent(self) {
self.parent
}
///|
pub impl Show for FCmpInst with output(self, logger) {
let lhs_ty = self.lhs.getType()
let repr = self.getValueRepr()
let lhs_repr = self.lhs.getValueRepr()
let rhs_repr = self.rhs.getValueRepr()
logger.write_string(
" \{repr} = \{self.predicate} \{lhs_ty} \{lhs_repr}, \{rhs_repr}",
)
}