README

Kaida-Amethyst/MoonLLVM/IR does not have a README file

#
AbstractType

pub trait AbstractType : Type {
asAbstractTypeEnum(Self) -> AbstractTypeEnum
}

#
AggregateType

pub trait AggregateType : Type {
asAggregateTypeEnum(Self) -> AggregateTypeEnum
getIndexedType(Self, idxs : ArrayView[Int]) -> &Type?
}

#
Constant

pub trait Constant : Value {
asConstantEnum(Self) -> ConstantEnum
}

#
FPType

pub trait FPType : PrimitiveType {
asFPTypeEnum(Self) -> FPTypeEnum
getFPMantissaWidth(Self) -> Int
}

#
Floating

pub trait Floating : Show {
asEnum(Self) -> FloatingEnum
to_float64(Self) -> Double
}

impl Floating for Float
impl Floating for Double

#
GlobalValue

pub trait GlobalValue : Value {
getGlobalValueBase(Self) -> GlobalValueBase
asGlobalValueEnum(Self) -> GlobalValueEnum
getModule(Self) -> Module
getLinkage(Self) -> Linkage
setLinkage(Self, linkage : Linkage) -> Unit
setUnnamedAddr(Self, unnamed_addr : UnnamedAddr) -> Unit
}

#
InsertPoint

trait InsertPoint

#
Instruction

pub trait Instruction : Value {
getInstBase(Self) -> InstBase
asInstEnum(Self) -> InstEnum
getParent(Self) -> Function
getModule(Self) -> Module
getBasicBlock(Self) -> BasicBlock?
getInstName(Self) -> String?
isIndependent(Self) -> Bool
isTerminator(Self) -> Bool
next(Self) -> &Instruction?
prev(Self) -> &Instruction?
insertAfter(Self, &Instruction) -> Unit raise LLVMValueError
insertBefore(Self, &Instruction) -> Unit raise LLVMValueError
moveBefore(Self, &Instruction) -> Unit
moveAfter(Self, &Instruction) -> Unit
removeFromParent(Self) -> Unit
eraseFromParent(Self) -> Unit
}

#
IntegerNumber

trait IntegerNumber

#
IntegerType

pub trait IntegerType : PrimitiveType {
asIntegerTypeEnum(Self) -> IntegerTypeEnum
getBitMask(Self) -> UInt64
getSignBit(Self) -> UInt64
getExtendedType(Self) -> &IntegerType?
}

Collection of Int1Type, Int8Type, Int16Type, Int32Type, Int64Type

test {
let ctx = Context::new()
let i8ty : &IntegerType = ctx.getInt8Ty()
assert_eq(i8ty.getBitWidth(), 8)
inspect(i8ty.getExtendedType().unwrap(), content="i16")
assert_eq(i8ty.getBitMask(), 0xFF)
assert_eq(i8ty.getExtendedType().unwrap().getSignBit(), 0x8000)
let i32ty = i8ty.getExtendedType().unwrap().getExtendedType().unwrap()
inspect(i32ty, content="i32")
guard i32ty.asIntegerTypeEnum() is Int32Type(i32ty)
inspect(i32ty, content="i32")
}

#
Metadata

pub trait Metadata : Show {
asMetadataEnum(Self) -> MetadataEnum
}

#
NamedValue

pub trait NamedValue : Value {
}

#
NumberArray

pub trait NumberArray : Show {
asEnum(Self) -> NumberArrayEnum
}

#
PrimitiveType

pub trait PrimitiveType : Type {
asPrimitiveTypeEnum(Self) -> PrimitiveTypeEnum
getBitWidth(Self) -> Int
}

#
Signed

pub trait Signed : Show {
asEnum(Self) -> SignedEnum
convert_to_int64(Self) -> Int64
}

impl Signed for Int
impl Signed for Int16
impl Signed for Int64

#
Type

pub trait Type : Show + Hash {
getContext(Self) -> Context
asTypeEnum(Self) -> TypeEnum
is16bitFPTy(Self) -> Bool
isIEEELikeFPTy(Self) -> Bool
isFloatingPointTy(Self) -> Bool
isScalableTargetExtTy(Self) -> Bool
isScalableTy(Self) -> Bool
isFPOrFPVectorTy(Self) -> Bool
isIntOrIntVectorTy(Self) -> Bool
isIntOrPtrTy(Self) -> Bool
isPtrOrPtrVectorTy(Self) -> Bool
canLosslesslyBitCastTo(Self, ty : &Type) -> Bool
isEmptyTy(Self) -> Bool
isFirstClassType(Self) -> Bool
isSingleValueType(Self) -> Bool
isAggregateType(Self) -> Bool
isSized(Self) -> Bool
isValidGEPType(Self) -> Bool
getPrimitiveSizeInBits(Self) -> TypeSize
getScalarSizeInBits(Self) -> Int
getScalarType(Self) -> &Type
tryAsFPType(Self) -> &FPType?
tryAsFPTypeEnum(Self) -> FPTypeEnum?
tryAsIntType(Self) -> &IntegerType?
tryAsIntTypeEnum(Self) -> IntegerTypeEnum?
tryAsPrimitiveType(Self) -> &PrimitiveType?
tryAsPrimitiveTypeEnum(Self) -> PrimitiveTypeEnum?
tryAsAggregateType(Self) -> &AggregateType?
tryAsAggregateTypeEnum(Self) -> AggregateTypeEnum?
tryAsAbstractType(Self) -> &AbstractType?
tryAsAbstractTypeEnum(Self) -> AbstractTypeEnum?
}

#
UnSigned

pub trait UnSigned : Show {
asEnum(Self) -> UnSignedEnum
convert_to_uint64(Self) -> UInt64
convert_to_int64(Self) -> Int64
}

impl UnSigned for UInt
impl UnSigned for UInt16
impl UnSigned for UInt64

#
UnaryInst

pub trait UnaryInst : Instruction {
asUnaryInstEnum(Self) -> UnaryInstEnum
}

#
User

pub trait User : Value {
asUserEnum(Self) -> UserEnum
getUserBase(Self) -> UserBase
getOperands(Self) -> Array[&Value]
getOperand(Self, index : Int) -> &Value?
getNumOperands(Self) -> Int
}

#
Value

pub trait Value : Show {
getValueBase(Self) -> ValueBase
asValueEnum(Self) -> ValueEnum
getType(Self) -> &Type
getContext(Self) -> Context
addUser(Self, user : &User) -> Unit
getValueRepr(Self) -> String
getName(Self) -> String?
setName(Self, name : String) -> Unit raise LLVMValueError
removeName(Self) -> Unit raise LLVMValueError
getNameOrSlot(Self) ->
Either
[String, UInt64]?
getNameOrSlotStr(Self) -> String
replaceAllUsersWith(Self, other : &Value) -> Unit
getUsers(Self) -> Array[&User]?
user_empty(Self) -> Bool
tryAsConstant(Self) -> &Constant?
tryAsConstantEnum(Self) -> ConstantEnum?
tryAsUser(Self) -> &User?
tryAsUserEnum(Self) -> UserEnum?
tryAsInst(Self) -> &Instruction?
tryAsInstEnum(Self) -> InstEnum?
tryAsGlobalValue(Self) -> &GlobalValue?
tryAsGlobalValueEnum(Self) -> GlobalValueEnum?
}

#
LLVMTypeError

type LLVMTypeError

#
LLVMValueError

pub suberror LLVMValueError {
LLVMValueError(String)
}

#
AbstractTypeEnum

pub enum AbstractTypeEnum {
VoidType(VoidType)
LabelType(LabelType)
MetadataType(MetadataType)
TokenType(TokenType)
FunctionType(FunctionType)
}

#
AddressSpace

pub type AddressSpace UInt

Memory address space of a pointer type.
impl Eq for AddressSpace

#
AddressSpace::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn AddressSpace::inner(self : AddressSpace) -> UInt
Convert newtype to its underlying type, automatically derived.

#
AddressSpace::new

fn AddressSpace::new(v : UInt) -> AddressSpace

#
AggregateTypeEnum

pub enum AggregateTypeEnum {
StructType(StructType)
ArrayType(ArrayType)
VectorType(VectorType)
ScalableVectorType(ScalableVectorType)
}

#
AggregateTypeEnum::asTypeClass

fn AggregateTypeEnum::asTypeClass(self : AggregateTypeEnum) -> &Type

#
AggregateTypeEnum::getIndexedType

fn AggregateTypeEnum::getIndexedType(self : AggregateTypeEnum, idxs : ArrayView[Int]) -> &Type?

#
AggregateTypeEnum::toTypeEnum

fn AggregateTypeEnum::toTypeEnum(self : AggregateTypeEnum) -> TypeEnum

#
Align

type Align

impl Eq for Align
impl Show for Align

#
Align::new

fn Align::new(v : UInt64) -> Align

#
Align::to_int64

fn Align::to_int64(self : Align) -> Int64

#
AllocaInst

pub struct AllocaInst {
uid : UInt64
vty : &Type
users : Array[&User]
name : String?
parent : Function
data_ty : &Type
align : Align
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
}

Alloca Instruction allocates memory on the stack for a variable.

Note:

Use IRBuilder::createAlloca to create an AllocaInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let void_ty = ctx.getVoidTy()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(void_ty, [])
let fval = mod.addFunction(fty, "foo")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let inst = builder.createAlloca(i32_ty, name="var1")
inspect(inst, content=" %var1 = alloca i32, align 4")
}
impl Value for AllocaInst
impl Show for AllocaInst

#
Argument

pub struct Argument {
uid : UInt64
vty : &Type
users : Array[&User]
parent : Function
argNo : UInt
name : String?
}

Argument of a function.

  • See llvm::Argument.

test {
let ctx = Context::new()
let prog = ctx.addModule("demo")
let i32ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32ty, [i32ty, i32ty])
let f = prog.addFunction(fty, "add")
let arg0 = f.getArg(0).unwrap()
let arg1 = f.getArg(1).unwrap()
inspect(arg0, content="i32 %0")
inspect(arg1.getType(), content="i32")
assert_true(f.getArg(2) is None)
}
impl Value for Argument
impl Show for Argument

#
Argument::addAttr

fn Argument::addAttr(self : Argument, attr : ParamAttr) -> Unit

Assign an attribute to the argument.

  • See llvm::Argument::addAttribute.

```mbt test` let ctx = Context::new() let prog = ctx.addModule("demo")

let i32ty = ctx.getInt32Ty() let fty = ctx.getFunctionType(i32ty, [i32ty, i32ty])

let fval = prog.addFunction(fty, "add")

let arg0 = f.getArg(0).unwrap() let arg1 = f.getArg(1).unwrap()

arg0.addAttr(NoAlias) inspect(fval, content="declare i32 @add(i32 noalias, i32)")

arg1.addAttr(NonNull) inspect(fval, content="declare i32 @add(i32 noalias, i32 nonnull)")

#
Argument::getModule

fn Argument::getModule(self : Argument) -> Module

#
ArrayType

pub struct ArrayType {
ctx : Context
elementType : &Type
elementCount : Int
}

ArrayType

  • See LLVM: ArrayType::get.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let arrty = ctx.getArrayType(i32ty, 16)
inspect(arrty, content="[16 x i32]")
assert_eq(arrty.getElementCount(), 16)
inspect(arrty.getElementType(), content="i32")
}
impl Type for ArrayType
impl Eq for ArrayType
impl Hash for ArrayType
impl Show for ArrayType

#
ArrayType::getElementCount

fn ArrayType::getElementCount(self : ArrayType) -> Int

#
ArrayType::getElementType

fn ArrayType::getElementType(self : ArrayType) -> &Type

#
AtomicOrdering

pub(all) enum AtomicOrdering {
NotAtomic
Unordered
Monotonic
Acquire
Release
AcquireRelease
SequentiallyConsistent
}

#
AttributeSet

type AttributeSet

#
BFloatType

pub struct BFloatType {
ctx : Context
}

BFloatType
impl Type for BFloatType
impl Eq for BFloatType
impl Hash for BFloatType
impl Show for BFloatType

#
BasicBlock

pub struct BasicBlock {
uid : UInt64
users : Array[&User]
parent : Function
name : String?
head : &Instruction?
id : Int
preds : Array[BasicBlock]
}

Block of instructions in a function.

Note:

Use Function::addBasicBlock to create a new BasicBlock.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "ret_42")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let forty_two = ctx.getConstInt32(42)
let _ = builder.createRet(forty_two)
inspect(
bb,
content=(
#|entry:
#| ret i32 42
#|
),
)
}
impl Value for BasicBlock
impl Eq for BasicBlock
impl Hash for BasicBlock
impl Show for BasicBlock

#
BasicBlock::firstInst

fn BasicBlock::firstInst(self : BasicBlock) -> &Instruction?

Get the first instruction in the basic block.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "ret_42")
let arg0 = fval.getArg(0).unwrap()
let arg1 = fval.getArg(1).unwrap()
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let sum1 = builder.createAdd(arg0, arg1, name="sum1")
let sum2 = builder.createAdd(arg0, arg1, name="sum2")
let mul = builder.createMul(sum1, sum2, name="mul")
let _ = builder.createRet(mul)
inspect(bb.firstInst().unwrap(), content=" %sum1 = add i32 %0, %1")
}

#
BasicBlock::getLabel

fn BasicBlock::getLabel(self : BasicBlock) -> String

#
BasicBlock::getModule

fn BasicBlock::getModule(self : BasicBlock) -> Module

#
BasicBlock::getParent

fn BasicBlock::getParent(self : BasicBlock) -> Function

#
BasicBlock::getSuccessors

fn BasicBlock::getSuccessors(self : BasicBlock) -> Array[BasicBlock]

#
BasicBlock::getTerminator

fn BasicBlock::getTerminator(self : BasicBlock) -> &Instruction?

#
BasicBlock::instIter

fn BasicBlock::instIter(self : BasicBlock) -> Iter[&Instruction]

#
BasicBlock::lastInst

fn BasicBlock::lastInst(self : BasicBlock) -> &Instruction?

Get the last instruction in the basic block.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "ret_42")
let arg0 = fval.getArg(0).unwrap()
let arg1 = fval.getArg(1).unwrap()
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let sum1 = builder.createAdd(arg0, arg1, name="sum1")
let sum2 = builder.createAdd(arg0, arg1, name="sum2")
let mul = builder.createMul(sum1, sum2, name="mul")
let _ = builder.createRet(mul)
inspect(bb.lastInst().unwrap(), content=" ret i32 %mul")
}

#
BasicBlock::removeFromParent

fn BasicBlock::removeFromParent(self : BasicBlock) -> Unit

#
BinaryInst

pub struct BinaryInst {
uid : UInt64
vty : &Type
users : Array[&User]
name : String?
lhs : &Value
rhs : &Value
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
opcode : BinaryOps
flags :
Set
[BinaryOpFlags]
fast_math_flags :
Set
[FastMathFlag]
}

BinaryInst represents a binary operation instruction that performs arithmetic or logical operations on two operands.

Note:

Use IRBuilder::createAdd, IRBuilder::createSub, IRBuilder::createMul, etc. to create binary instructions.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "binary_ops_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let add = builder.createAdd(arg1, arg2, name="sum")
inspect(add, content=" %sum = add i32 %0, %1")
assert_true(add.asValueEnum() is BinaryInst(_))
let sub = builder.createSub(arg1, arg2, name="diff")
inspect(sub, content=" %diff = sub i32 %0, %1")
let mul = builder.createMul(arg1, arg2, name="product")
inspect(mul, content=" %product = mul i32 %0, %1")
let and_result = builder.createAnd(arg1, arg2, name="and_result")
inspect(and_result, content=" %and_result = and i32 %0, %1")
let or_result = builder.createOr(arg1, arg2, name="or_result")
inspect(or_result, content=" %or_result = or i32 %0, %1")
let xor_result = builder.createXor(arg1, arg2, name="xor_result")
inspect(xor_result, content=" %xor_result = xor i32 %0, %1")
}
impl User for BinaryInst
impl Value for BinaryInst
impl Show for BinaryInst

#
BinaryOpFlags

pub enum BinaryOpFlags {
NoUnsignedWrap
NoSignedWrap
Exact
}

impl Eq for BinaryOpFlags

#
BinaryOps

pub enum BinaryOps {
Add
FAdd
Sub
FSub
Mul
FMul
SDiv
UDiv
FDiv
URem
SRem
FRem
Shl
LShr
AShr
And
Or
Xor
}

impl Eq for BinaryOps
impl Hash for BinaryOps
impl Show for BinaryOps

#
BranchInst

pub struct BranchInst {
uid : UInt64
vty : VoidType
condition : &Value?
trueBlock : BasicBlock?
falseBlock : BasicBlock?
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
}

BranchInst represents a branch instruction that transfers control flow to different basic blocks.

Note:

Use IRBuilder::createBr for unconditional branches or IRBuilder::createCondBr for conditional branches.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i1_ty = ctx.getInt1Ty()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [i1_ty])
let fval = mod.addFunction(fty, "branch_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let true_bb = fval.addBasicBlock(name="true_branch")
let false_bb = fval.addBasicBlock(name="false_branch")
let cond = fval.getArg(0).unwrap()
builder.setInsertPoint(entry_bb)
let cond_br = builder.createCondBr(cond, true_bb, false_bb)
inspect(
cond_br,
content=" br i1 %0, label %true_branch, label %false_branch",
)
assert_true(cond_br.asValueEnum() is BranchInst(_))
builder.setInsertPoint(true_bb)
let uncond_br = builder.createBr(false_bb)
inspect(uncond_br, content=" br label %false_branch")
}
impl User for BranchInst
impl Value for BranchInst
impl Show for BranchInst

#
BranchInst::getNumSuccessors

fn BranchInst::getNumSuccessors(self : BranchInst) -> Int

#
BranchInst::getSuccessor

fn BranchInst::getSuccessor(self : BranchInst, idx : Int) -> BasicBlock?

#
BranchInst::isConditional

fn BranchInst::isConditional(self : BranchInst) -> Bool

#
BranchInst::isUnconditional

fn BranchInst::isUnconditional(self : BranchInst) -> Bool

#
CallInst

pub struct CallInst {
uid : UInt64
vty : &Type
users : Array[&User]
name : String?
function_type : FunctionType
callee :
Either
[Function, &Value]
args : Array[&Value]
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
tailCallKind : TailCallKind
}

CallInst represents a function call instruction that invokes a function with the specified arguments.

Note:

Use IRBuilder::createCall to create a CallInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let add_fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let main_fty = ctx.getFunctionType(i32_ty, [])
let add_func = mod.addFunction(add_fty, "add")
let main_func = mod.addFunction(main_fty, "main")
let bb = main_func.addBasicBlock(name="entry")
let arg1 = ctx.getConstInt32(10)
let arg2 = ctx.getConstInt32(20)
builder.setInsertPoint(bb)
let call = builder.createCall(add_func, [arg1, arg2], name="sum")
inspect(call, content=" %sum = call i32 @add(i32 10, i32 20)")
assert_true(call.asValueEnum() is CallInst(_))
let void_fty = ctx.getFunctionType(ctx.getVoidTy(), [])
let void_func = mod.addFunction(void_fty, "void_func")
let void_call = builder.createCall(void_func, [])
inspect(void_call, content=" call void @void_func()")
}
impl User for CallInst
impl Value for CallInst
impl Show for CallInst

#
CallInst::getArgOperand

fn CallInst::getArgOperand(self : CallInst, idx : Int) -> &Value?

#
CallInst::getCallee

fn CallInst::getCallee(self : CallInst) -> Function

#
CallInst::getFunctionType

fn CallInst::getFunctionType(self : CallInst) -> FunctionType

#
CallInst::getNumArgs

fn CallInst::getNumArgs(self : CallInst) -> Int

#
CallInst::getTailCallKind

fn CallInst::getTailCallKind(self : CallInst) -> TailCallKind

#
CallInst::isTailCall

fn CallInst::isTailCall(self : CallInst) -> Bool

#
CallInst::setTailCallKind

fn CallInst::setTailCallKind(self : CallInst, tailCallKind : TailCallKind) -> Unit

#
CastInst

pub struct CastInst {
uid : UInt64
to_ty : &Type
from_val : &Value
name : String?
parent : Function
users : Array[&User]
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
opcode : CastOps
}

CastInst represents a type conversion instruction that converts a value from one type to another.

Note:

Use IRBuilder::createTrunc, IRBuilder::createZExt, IRBuilder::createSExt, etc. to create cast instructions.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let i64_ty = ctx.getInt64Ty()
let f32_ty = ctx.getFloatTy()
let fty = ctx.getFunctionType(i32_ty, [i64_ty])
let fval = mod.addFunction(fty, "cast_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let trunc = builder.createTrunc(arg, i32_ty, name="truncated")
inspect(trunc, content=" %truncated = trunc i64 %0 to i32")
assert_true(trunc.asValueEnum() is CastInst(_))
let zext = builder.createZExt(trunc, i64_ty, name="extended")
inspect(zext, content=" %extended = zext i32 %truncated to i64")
let bitcast = builder.createBitCast(trunc, f32_ty, name="bits")
inspect(bitcast, content=" %bits = bitcast i32 %truncated to float")
}
impl User for CastInst
impl Value for CastInst
impl Show for CastInst

#
CastOps

pub(all) enum CastOps {
Trunc
ZExt
SExt
FPTrunc
FPExt
UIToFP
SIToFP
FPToUI
FPToSI
PtrToInt
IntToPtr
BitCast
}

impl Eq for CastOps
impl Hash for CastOps
impl Show for CastOps

#
ConstantArray

pub struct ConstantArray {
uid : UInt64
vty : ArrayType
data :
Either
[Array[&Constant], NumberArrayEnum]
}

impl Eq for ConstantArray

#
ConstantEnum

pub enum ConstantEnum {
ConstantInt(ConstantInt)
ConstantFP(ConstantFP)
ConstantPointerNull(ConstantPointerNull)
ConstantArray(ConstantArray)
ConstantVector(ConstantVector)
ConstantString(ConstantString)
ConstantStruct(ConstantStruct)
}

impl Eq for ConstantEnum

#
ConstantFP

pub struct ConstantFP {
uid : UInt64
vty : &FPType
value : Double
}

impl Value for ConstantFP
impl Eq for ConstantFP
impl Show for ConstantFP

#
ConstantFP::add

fn ConstantFP::add(self : ConstantFP, other : ConstantFP) -> ConstantFP raise LLVMValueError

Add two ConstantFP, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantFP are not the same.

test {
let ctx = Context::new()
let f32_0 = ctx.getConstFloat(0.0)
let f32_1_5 = ctx.getConstFloat(1.5)
let result1 = f32_0.add(f32_1_5)
assert_eq(result1.getValue(), 1.5)
let f64_2_5 = ctx.getConstDouble(2.5)
let f64_m1_5 = ctx.getConstDouble(-1.5)
let result2 = f64_2_5.add(f64_m1_5)
assert_eq(result2.getValue(), 1.0)
}

#
ConstantFP::bitcast

fn ConstantFP::bitcast(self : ConstantFP, dst_ty : &PrimitiveType) -> &Constant raise LLVMValueError

Bitcast this ConstantFP to another primitive type of the same bit width, useful in constant folding.

Note: It will raise BitCastInstTypeMismatch if the types have different bit widths or if the cast is invalid. It will raise BitCastOnlyAcceptPrimitiveTypes if the source is not a primitive type.

test {
let ctx = Context::new()

// Test f32 to i32 bitcast
let f32_2_0 = ctx.getConstFloat(2.0)
let i32_bits = f32_2_0.bitcast(ctx.getInt32Ty())
guard i32_bits.asConstantEnum() is ConstantInt(i32_bits)
assert_eq(i32_bits.getValueAsInt64(), 0x40000000) // 2.0f bit pattern

// Test f64 to i64 bitcast
let f64_2_0 = ctx.getConstDouble(2.0)
let i64_bits = f64_2_0.bitcast(ctx.getInt64Ty())
guard i64_bits.asConstantEnum() is ConstantInt(i64_bits)
assert_eq(i64_bits.getValueAsInt64(), 0x4000000000000000L) // 2.0 bit pattern

// Test f32 to f32 (same type should error)
let f32_val = ctx.getConstFloat(1.0)
assert_true((try! f32_val.bitcast(ctx.getFloatTy())) is Err(_))

// Test error case: different bit widths
let f64_val = ctx.getConstDouble(42.0)
assert_true((try! f64_val.bitcast(ctx.getInt32Ty())) is Err(_))
}

#
ConstantFP::compare

fn ConstantFP::compare(self : ConstantFP, predicate : FloatPredicate, other : ConstantFP) -> ConstantInt raise LLVMValueError

Compare two ConstantFP using the given predicate, useful in constant folding.

Note: It will raise TypeMismatchForCmpInst if the types of two ConstantFP are not the same. Only FCMP_xxx predicates are supported.

test {
let ctx = Context::new()
let f32_1_5 = ctx.getConstFloat(1.5)
let f32_2_5 = ctx.getConstFloat(2.5)
let f32_nan = ctx.getConstFloat(0.0 / 0.0)

// Test FCMP_OEQ (ordered equal)
inspect(f32_1_5.compare(OEQ, f32_1_5), content="i1 true")
inspect(f32_1_5.compare(OEQ, f32_2_5), content="i1 false")
inspect(f32_nan.compare(OEQ, f32_nan), content="i1 false") // NaN != NaN

// Test UEQ (unordered equal)
inspect(f32_1_5.compare(UEQ, f32_1_5), content="i1 true")
inspect(f32_nan.compare(UEQ, f32_nan), content="i1 true") // NaN == NaN in unordered

// Test OGT (ordered greater than)
inspect(f32_2_5.compare(OGT, f32_1_5), content="i1 true")
inspect(f32_1_5.compare(OGT, f32_2_5), content="i1 false")
inspect(f32_nan.compare(OGT, f32_1_5), content="i1 false") // NaN comparisons are false

// Test UGT (unordered greater than)
inspect(f32_2_5.compare(UGT, f32_1_5), content="i1 true")
inspect(f32_nan.compare(UGT, f32_1_5), content="i1 true") // NaN makes it unordered

// Test OLT (ordered less than)
inspect(f32_1_5.compare(OLT, f32_2_5), content="i1 true")
inspect(f32_2_5.compare(OLT, f32_1_5), content="i1 false")

// Test ORD (ordered - no NaNs)
inspect(f32_1_5.compare(ORD, f32_2_5), content="i1 true")
inspect(f32_nan.compare(ORD, f32_1_5), content="i1 false")

// Test UNO (unordered - has NaNs)
inspect(f32_1_5.compare(UNO, f32_2_5), content="i1 false")
inspect(f32_nan.compare(UNO, f32_1_5), content="i1 true")

// Test TRUE and FCMP_FALSE
inspect(f32_1_5.compare(TRUE, f32_2_5), content="i1 true")
inspect(f32_1_5.compare(FALSE, f32_2_5), content="i1 false")

// Test type mismatch
let f64_1_5 = ctx.getConstDouble(1.5)
assert_true((try! f32_1_5.compare(OEQ, f64_1_5)) is Err(_))
}

#
ConstantFP::div

fn ConstantFP::div(self : ConstantFP, other : ConstantFP) -> ConstantFP raise LLVMValueError

Divide two ConstantFP, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantFP are not the same.

test {
let ctx = Context::new()
let f32_0 = ctx.getConstFloat(0.0)
let f32_1_5 = ctx.getConstFloat(1.5)
let result1 = f32_0.div(f32_1_5)
assert_eq(result1.getValue(), 0.0)
let f64_2_5 = ctx.getConstDouble(2.5)
let f64_m1_5 = ctx.getConstDouble(-1.5)
let result2 = f64_2_5.div(f64_m1_5)
assert_eq(result2.getValue(), -5.0 / 3.0)
}

#
ConstantFP::equals

fn[T : Floating + Show] ConstantFP::equals(self : ConstantFP, value : T) -> Bool

#
ConstantFP::exactlyEquals

fn[T : Floating + Show] ConstantFP::exactlyEquals(self : ConstantFP, value : T) -> Bool

#
ConstantFP::fpext

fn ConstantFP::fpext(self : ConstantFP, dst_ty : &FPType) -> ConstantFP raise LLVMValueError

Extend this ConstantFP to a larger floating-point type, useful in constant folding.

Note: It will raise FPExtCastInstTypeMismatch if the source type bit width is not less than the destination type bit width.

test {
let ctx = Context::new()

// Test f32 to f64 extension
let f32_1_5 = ctx.getConstFloat(1.5)
let f64_1_5 = f32_1_5.fpext(ctx.getDoubleTy())
assert_eq(f64_1_5.getValue(), 1.5)

// Test f32 to f64 extension preserves value
let f32_pi = ctx.getConstFloat(3.14159265)
let f64_pi = f32_pi.fpext(ctx.getDoubleTy())
assert_eq(f64_pi.getValue(), 3.1415927410125732)

// Test error case: cannot extend to smaller type
let f64_val = ctx.getConstDouble(2.0)
assert_true((try! f64_val.fpext(ctx.getFloatTy())) is Err(_))
}

#
ConstantFP::fptosi

fn ConstantFP::fptosi(self : ConstantFP, dst_ty : &IntegerType) -> ConstantInt

Convert this ConstantFP to a signed integer type, useful in constant folding.

Note: It will raise FPToSIInstTypeMismatch if the source is not a floating-point type. The conversion truncates towards zero (similar to C cast).

test {
let ctx = Context::new()

// Test positive float to signed integer
let f32_3_7 = ctx.getConstFloat(3.7)
let i32_3 = f32_3_7.fptosi(ctx.getInt32Ty())
assert_eq(i32_3.getValueAsInt64(), 3)

// Test negative float to signed integer
let f64_m5_2 = ctx.getConstDouble(-5.2)
let i64_m5 = f64_m5_2.fptosi(ctx.getInt64Ty())
assert_eq(i64_m5.getValueAsInt64(), -5)

// Test zero conversion
let f32_0 = ctx.getConstFloat(0.0)
let i16_0 = f32_0.fptosi(ctx.getInt16Ty())
assert_eq(i16_0.getValueAsInt64(), 0)

// Test fractional part truncation
let f64_m9_9 = ctx.getConstDouble(-9.9)
let i32_m9 = f64_m9_9.fptosi(ctx.getInt32Ty())
assert_eq(i32_m9.getValueAsInt64(), -9)
}

#
ConstantFP::fptoui

fn ConstantFP::fptoui(self : ConstantFP, dst_ty : &IntegerType) -> ConstantInt

Convert this ConstantFP to an unsigned integer type, useful in constant folding.

Note: It will raise FPToUIInstTypeMismatch if the source is not a floating-point type. The conversion truncates towards zero (similar to C cast).

test {
let ctx = Context::new()

// Test positive float to unsigned integer
let f32_3_7 = ctx.getConstFloat(3.7)
let i32_3 = f32_3_7.fptoui(ctx.getInt32Ty())
assert_eq(i32_3.getValueAsInt64(), 3)

// Test zero conversion
let f64_0 = ctx.getConstDouble(0.0)
let i64_0 = f64_0.fptoui(ctx.getInt64Ty())
assert_eq(i64_0.getValueAsInt64(), 0)

// Test large float to i8 (overflow behavior)
let f32_1000 = ctx.getConstFloat(1000.0)
let i8_overflow = f32_1000.fptoui(ctx.getInt8Ty())
// The value will be truncated to fit in i8 range (1000 in i8 is -24)
assert_eq(i8_overflow.getValueAsInt64(), -24)

// Test fractional part truncation
let f64_9_9 = ctx.getConstDouble(9.9)
let i32_9 = f64_9_9.fptoui(ctx.getInt32Ty())
assert_eq(i32_9.getValueAsInt64(), 9)
}

#
ConstantFP::fptrunc

fn ConstantFP::fptrunc(self : ConstantFP, dst_ty : &FPType) -> ConstantFP raise LLVMValueError

Truncate this ConstantFP to a smaller floating-point type, useful in constant folding.

Note: It will raise FPTruncCastInstTypeMismatch if the source type bit width is not greater than the destination type bit width.

test {
let ctx = Context::new()

// Test f64 to f32 truncation
let f64_1_5 = ctx.getConstDouble(1.5)
let f32_1_5 = f64_1_5.fptrunc(ctx.getFloatTy())
assert_eq(f32_1_5.getValue(), 1.5)

// Test f64 to f32 truncation with another value
let f64_precise = ctx.getConstDouble(2.5)
let f32_truncated = f64_precise.fptrunc(ctx.getFloatTy())
// In constant folding, the value is preserved
assert_eq(f32_truncated.getValue(), 2.5)

// Test error case: cannot truncate to larger type
let f32_val = ctx.getConstFloat(2.0)
assert_true((try! f32_val.fptrunc(ctx.getDoubleTy())) is Err(_))
}

#
ConstantFP::getFPType

fn ConstantFP::getFPType(self : ConstantFP) -> &FPType

#
ConstantFP::getValue

fn ConstantFP::getValue(self : ConstantFP) -> Double

#
ConstantFP::mul

fn ConstantFP::mul(self : ConstantFP, other : ConstantFP) -> ConstantFP raise LLVMValueError

Multiply two ConstantFP, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantFP are not the same.

test {
let ctx = Context::new()
let f32_0 = ctx.getConstFloat(0.0)
let f32_1_5 = ctx.getConstFloat(1.5)
let result1 = f32_0.mul(f32_1_5)
assert_eq(result1.getValue(), 0.0)
let f64_2_5 = ctx.getConstDouble(2.5)
let f64_m1_5 = ctx.getConstDouble(-1.5)
let result2 = f64_2_5.mul(f64_m1_5)
assert_eq(result2.getValue(), -3.75)
}

#
ConstantFP::sub

fn ConstantFP::sub(self : ConstantFP, other : ConstantFP) -> ConstantFP raise LLVMValueError

Subtract two ConstantFP, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantFP are not the same.

test {
let ctx = Context::new()
let f32_0 = ctx.getConstFloat(0.0)
let f32_1_5 = ctx.getConstFloat(1.5)
let result1 = f32_0.sub(f32_1_5)
assert_eq(result1.getValue(), -1.5)
let f64_2_5 = ctx.getConstDouble(2.5)
let f64_m1_5 = ctx.getConstDouble(-1.5)
let result2 = f64_2_5.sub(f64_m1_5)
assert_eq(result2.getValue(), 4.0)
}

#
ConstantInt

pub struct ConstantInt {
uid : UInt64
vty : &IntegerType
value : Int64
}

ConstantInt

Use Context::getConstInt8, getConstInt16, getConstInt32, getConstInt64 To create a new ConstantInt.

test {
let ctx = Context::new()
let i8 = ctx.getConstInt8(0)
let i16 = ctx.getConstInt16(1)
let i32 = ctx.getConstInt32(-2)
let i64 = ctx.getConstInt64(16)
inspect(i8, content="i8 0")
inspect(i16, content="i16 1")
inspect(i32, content="i32 -2")
inspect(i64, content="i64 16")
}
impl Eq for ConstantInt
impl Show for ConstantInt

#
ConstantInt::add

Add two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_0 = ctx.getConstInt8(0)
let i8_31 = ctx.getConstInt8(31)
inspect(i8_0.add(i8_31), content="i8 31")
let i16_5 = ctx.getConstInt16(5)
let i16_72 = ctx.getConstInt16(72)
inspect(i16_5.add(i16_72), content="i16 77")
let i32_m7 = ctx.getConstInt32(-7)
let i32_81 = ctx.getConstInt32(81)
inspect(i32_m7.add(i32_81), content="i32 74")
let i64_16 = ctx.getConstInt64(16)
let i64_m33 = ctx.getConstInt64(-33)
inspect(i64_16.add(i64_m33), content="i64 -17")
assert_true((try! i8_0.add(i16_5)) is Err(_))
}

#
ConstantInt::ashr

fn ConstantInt::ashr(self : ConstantInt, other : ConstantInt) -> ConstantInt raise LLVMValueError

Arithmetic right shift (ashr) two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_m1 = ctx.getConstInt8(-1) // 11111111
let i8_2 = ctx.getConstInt8(2) // shift by 2
inspect(i8_m1.ashr(i8_2), content="i8 -1") // 11111111 (sign extended)
let i16_m16 = ctx.getConstInt16(-16) // ...1111111111110000
let i16_2 = ctx.getConstInt16(2) // shift by 2
inspect(i16_m16.ashr(i16_2), content="i16 -4") // ...1111111111111100
let i32_m8 = ctx.getConstInt32(-8)
let i32_1 = ctx.getConstInt32(1)
inspect(i32_m8.ashr(i32_1), content="i32 -4") // -8 >> 1 = -4 (arithmetic)
let i64_m128 = ctx.getConstInt64(-128L)
let i64_3 = ctx.getConstInt64(3L)
inspect(i64_m128.ashr(i64_3), content="i64 -16") // -128 >> 3 = -16

// Positive numbers should behave like logical shift
let i32_64 = ctx.getConstInt32(64)
let i32_2 = ctx.getConstInt32(2)
inspect(i32_64.ashr(i32_2), content="i32 16") // 64 >> 2 = 16
}

#
ConstantInt::bitcast

fn ConstantInt::bitcast(self : ConstantInt, dst_ty : &PrimitiveType) -> &Constant raise LLVMValueError

Bitcast this ConstantInt to another primitive type of the same bit width, useful in constant folding.

Note: It will raise BitCastInstTypeMismatch if the types have different bit widths or if the cast is invalid. It will raise BitCastOnlyAcceptPrimitiveTypes if the source is not a primitive type.

test {
let ctx = Context::new()

// Test i32 to f32 bitcast
let i32_val = ctx.getConstInt32(0x40000000) // 2.0 in float
let f32_val = i32_val.bitcast(ctx.getFloatTy())
guard f32_val.asConstantEnum() is ConstantFP(f32_val)
assert_eq(f32_val.getValue(), 2.0)

// Test i64 to f64 bitcast
let i64_val = ctx.getConstInt64(0x4000000000000000L) // 2.0 in double
let f64_val = i64_val.bitcast(ctx.getDoubleTy())
guard f64_val.asConstantEnum() is ConstantFP(f64_val)
assert_eq(f64_val.getValue(), 2.0)

// Test error case: different bit widths
let i8_val = ctx.getConstInt8(42)
assert_true((try! i8_val.bitcast(ctx.getFloatTy())) is Err(_))
}

#
ConstantInt::compare

fn ConstantInt::compare(self : ConstantInt, predicate : IntPredicate, other : ConstantInt) -> ConstantInt raise LLVMValueError

Compare two ConstantInt using the given predicate, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same. Only ICMP_xxx predicates are supported.

test {
let ctx = Context::new()
let i8_5 = ctx.getConstInt8(5)
let i8_10 = ctx.getConstInt8(10)
let i8_m5 = ctx.getConstInt8(-5)

// Test EQ
inspect(i8_5.compare(EQ, i8_5), content="i1 true")
inspect(i8_5.compare(EQ, i8_10), content="i1 false")

// Test NE
inspect(i8_5.compare(NE, i8_10), content="i1 true")
inspect(i8_5.compare(NE, i8_5), content="i1 false")

// Test SGT (signed greater than)
inspect(i8_10.compare(SGT, i8_5), content="i1 true")
inspect(i8_5.compare(SGT, i8_10), content="i1 false")
inspect(i8_5.compare(SGT, i8_m5), content="i1 true")

// Test UGT (unsigned greater than)
let i8_200 = ctx.getConstInt8(200) // -56 as signed, 200 as unsigned
inspect(i8_200.compare(UGT, i8_10), content="i1 true")
inspect(i8_10.compare(UGT, i8_200), content="i1 false")

// Test SLT (signed less than)
inspect(i8_5.compare(SLT, i8_10), content="i1 true")
inspect(i8_m5.compare(SLT, i8_5), content="i1 true")

// Test ULE (unsigned less or equal)
inspect(i8_5.compare(ULE, i8_10), content="i1 true")
inspect(i8_5.compare(ULE, i8_5), content="i1 true")

// Test type mismatch
let i16_5 = ctx.getConstInt16(5)
assert_true((try! i8_5.compare(EQ, i16_5)) is Err(_))
}

#
ConstantInt::compute_and

fn ConstantInt::compute_and(self : ConstantInt, other : ConstantInt) -> ConstantInt raise LLVMValueError

Bitwise AND two ConstantInt, useful in constant folding.

test {
let ctx = Context::new()
let i8_6 = ctx.getConstInt8(6) // 00000110
let i8_3 = ctx.getConstInt8(3) // 00000011
inspect(i8_6.compute_and(i8_3), content="i8 2") // 00000010
let i16_m1 = ctx.getConstInt16(-1) // 1111111111111111
let i16_all_set = ctx.getConstInt16(-1)
inspect(i16_m1.compute_and(i16_all_set), content="i16 -1")
let i32_pattern = ctx.getConstInt32(0x0F0F0F0F)
let i32_mask = ctx.getConstInt32(0xFF00FF00)
inspect(i32_pattern.compute_and(i32_mask), content="i32 251662080") // 0x0F000F00
let i64_val = ctx.getConstInt64(0x123456789ABCDEF0L)
let i64_low_clear = ctx.getConstInt64(-1L << 4) // ...FFFFFFFFFFFFFFF0
inspect(i64_val.compute_and(i64_low_clear), content="i64 1311768467463790320") // 0x123456789ABCDEF0
}

#
ConstantInt::compute_shl

fn ConstantInt::compute_shl(self : ConstantInt, other : ConstantInt) -> ConstantInt raise LLVMValueError

Left shift (shl) two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_1 = ctx.getConstInt8(1) // 00000001
let i8_3 = ctx.getConstInt8(3) // shift by 3
inspect(i8_1.compute_shl(i8_3), content="i8 8") // 00001000
let i16_5 = ctx.getConstInt16(5) // ...00000101
let i16_2 = ctx.getConstInt16(2) // shift by 2
inspect(i16_5.compute_shl(i16_2), content="i16 20") // ...00010100
let i32_7 = ctx.getConstInt32(7)
let i32_4 = ctx.getConstInt32(4)
inspect(i32_7.compute_shl(i32_4), content="i32 112") // 7 << 4 = 112
let i64_val = ctx.getConstInt64(0x123L)
let i64_8 = ctx.getConstInt64(8L)
inspect(i64_val.compute_shl(i64_8), content="i64 74496") // 0x123 << 8 = 0x12300
}

#
ConstantInt::equals

fn[T : IntegerNumber + Show] ConstantInt::equals(self : ConstantInt, value : T) -> Bool

Compare the value of this constant int with a signed integer.

test {
let ctx = Context::new()
assert_true(ctx.getConstInt8(0).equals(0))
assert_true(ctx.getConstInt8(-1).equals(-1))
assert_true(ctx.getConstInt8(1).equals(1))
assert_true(ctx.getConstInt16(16).equals(16))
assert_true(ctx.getConstInt32(-128).equals(-128))
}

#
ConstantInt::getIntegerType

fn ConstantInt::getIntegerType(self : ConstantInt) -> &IntegerType

Get the type of constant int value.

test {
let ctx = Context::new()
let i8_zero = ctx.getConstInt8(0)
let i16_one = ctx.getConstInt16(1)
let i32_m2 = ctx.getConstInt32(-2)
let i64_m16 = ctx.getConstInt64(-16)
inspect(i8_zero.getIntegerType(), content="i8")
inspect(i16_one.getIntegerType(), content="i16")
inspect(i32_m2.getIntegerType(), content="i32")
inspect(i64_m16.getIntegerType(), content="i64")
}

#
ConstantInt::getValueAsInt64

fn ConstantInt::getValueAsInt64(self : ConstantInt) -> Int64

Get the value of this constant as a signed 64-bits integer.

test {
let ctx = Context::new()
let i8_zero = ctx.getConstInt8(0)
let i16_one = ctx.getConstInt16(1)
let i32_two = ctx.getConstInt32(2)
let i64_m1 = ctx.getConstInt64(-1)
let i8_m1 = ctx.getConstInt8(-1)
assert_eq(i8_zero.getValueAsInt64(), 0)
assert_eq(i16_one.getValueAsInt64(), 1)
assert_eq(i32_two.getValueAsInt64(), 2)
assert_eq(i64_m1.getValueAsInt64(), -1)
assert_eq(i8_m1.getValueAsInt64(), -1)
}

#
ConstantInt::inttoptr

Convert this ConstantInt to a pointer type, useful in constant folding.

Note: It will raise IntToPtrCastInstTypeMismatch if the source is not an integer type. For constant folding, this always returns a null pointer since we cannot create meaningful pointer constants from integer values at compile time.

test {
let ctx = Context::new()
let i64_0 = ctx.getConstInt64(0)
let null_ptr = i64_0.inttoptr()
inspect(null_ptr, content="ptr null")
let i32_42 = ctx.getConstInt32(42)
let ptr_42 = i32_42.inttoptr()
inspect(ptr_42, content="ptr null") // Still null in constant folding
}

#
ConstantInt::isMaxValue

fn ConstantInt::isMaxValue(self : ConstantInt) -> Bool

#
ConstantInt::isMinValue

fn ConstantInt::isMinValue(self : ConstantInt) -> Bool

#
ConstantInt::isNegative

fn ConstantInt::isNegative(self : ConstantInt) -> Bool

#
ConstantInt::lshr

fn ConstantInt::lshr(self : ConstantInt, other : ConstantInt) -> ConstantInt raise LLVMValueError

Logical right shift (lshr) two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_200 = ctx.getConstInt8(200) // 11001000 (as unsigned)
let i8_2 = ctx.getConstInt8(2) // shift by 2
inspect(i8_200.lshr(i8_2), content="i8 50") // 00110010 (50)
let i16_val = ctx.getConstInt16(-32768) // 1000000000000000
let i16_1 = ctx.getConstInt16(1) // shift by 1
inspect(i16_val.lshr(i16_1), content="i16 16384") // 0100000000000000 (16384)
let i32_m1 = ctx.getConstInt32(-1) // 0xFFFFFFFF
let i32_4 = ctx.getConstInt32(4) // shift by 4
inspect(i32_m1.lshr(i32_4), content="i32 268435455") // 0x0FFFFFFF
let i64_val = ctx.getConstInt64(0x8000000000000000L) // MSB set
let i64_1 = ctx.getConstInt64(1L)
inspect(i64_val.lshr(i64_1), content="i64 4611686018427387904") // logical shift
}

#
ConstantInt::mul

Multiply two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_0 = ctx.getConstInt8(0)
let i8_31 = ctx.getConstInt8(31)
inspect(i8_0.mul(i8_31), content="i8 0")
let i16_5 = ctx.getConstInt16(5)
let i16_72 = ctx.getConstInt16(72)
inspect(i16_5.mul(i16_72), content="i16 360")
let i32_m7 = ctx.getConstInt32(-7)
let i32_81 = ctx.getConstInt32(81)
inspect(i32_m7.mul(i32_81), content="i32 -567")
let i64_16 = ctx.getConstInt64(16)
let i64_m33 = ctx.getConstInt64(-33)
inspect(i64_16.mul(i64_m33), content="i64 -528")
}

#
ConstantInt::or

Bitwise OR two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_6 = ctx.getConstInt8(6) // 00000110
let i8_3 = ctx.getConstInt8(3) // 00000011
inspect(i8_6.or(i8_3), content="i8 7") // 00000111
let i16_1 = ctx.getConstInt16(1) // ...0001
let i16_2 = ctx.getConstInt16(2) // ...0010
inspect(i16_1.or(i16_2), content="i16 3") // ...0011
let i32_pattern = ctx.getConstInt32(0x0F0F0F0F)
let i32_mask = ctx.getConstInt32(0xF0F0F0F0)
inspect(i32_pattern.or(i32_mask), content="i32 -1") // 0xFFFFFFFF
let i64_val = ctx.getConstInt64(0L)
let i64_m1 = ctx.getConstInt64(-1L)
inspect(i64_val.or(i64_m1), content="i64 -1")
}

#
ConstantInt::sdiv

fn ConstantInt::sdiv(self : ConstantInt, other : ConstantInt) -> ConstantInt raise LLVMValueError

Divide two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_1 = ctx.getConstInt8(1)
let i8_31 = ctx.getConstInt8(31)
inspect(i8_31.sdiv(i8_1), content="i8 31")
let i16_5 = ctx.getConstInt16(5)
let i16_72 = ctx.getConstInt16(72)
inspect(i16_72.sdiv(i16_5), content="i16 14")
let i32_m7 = ctx.getConstInt32(-7)
let i32_81 = ctx.getConstInt32(81)
inspect(i32_m7.sdiv(i32_81), content="i32 0")
let i64_16 = ctx.getConstInt64(16)
let i64_m33 = ctx.getConstInt64(-33)
inspect(i64_16.sdiv(i64_m33), content="i64 0")
}

#
ConstantInt::sext

fn ConstantInt::sext(self : ConstantInt, dst_ty : &IntegerType) -> ConstantInt raise LLVMValueError

Sign extend this ConstantInt to a larger integer type, useful in constant folding.

Note: It will raise SExtCastInstTypeMismatch if the source type bit width is not less than the destination type bit width.

test {
let ctx = Context::new()
let i8_m1 = ctx.getConstInt8(-1)
let i32_m1 = i8_m1.sext(ctx.getInt32Ty())
inspect(i32_m1, content="i32 -1")
let i1_true = ctx.getConstTrue()
let i8_true = i1_true.sext(ctx.getInt8Ty())
inspect(i8_true, content="i8 -1")
let i16_42 = ctx.getConstInt16(42)
let i64_42 = i16_42.sext(ctx.getInt64Ty())
inspect(i64_42, content="i64 42")

// Test error case: cannot sext to smaller type
let i32_val = ctx.getConstInt32(42)
assert_true((try! i32_val.sext(ctx.getInt8Ty())) is Err(_))
}

#
ConstantInt::sitofp

fn ConstantInt::sitofp(self : ConstantInt, dst_ty : &FPType) -> ConstantFP

Convert this ConstantInt to a floating-point type (signed interpretation), useful in constant folding.

Note: It will raise SIToFPInstTypeMismatch if the source is not an integer type.

test {
let ctx = Context::new()
let i32_m42 = ctx.getConstInt32(-42)
let f32_m42 = i32_m42.sitofp(ctx.getFloatTy())
assert_eq(f32_m42.getValue(), -42.0)
let i8_127 = ctx.getConstInt8(127)
let f64_127 = i8_127.sitofp(ctx.getDoubleTy())
assert_eq(f64_127.getValue(), 127.0)
let i64_0 = ctx.getConstInt64(0)
let f32_0 = i64_0.sitofp(ctx.getFloatTy())
assert_eq(f32_0.getValue(), 0.0)
}

#
ConstantInt::sub

Subtract two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_0 = ctx.getConstInt8(0)
let i8_31 = ctx.getConstInt8(31)
inspect(i8_31.sub(i8_0), content="i8 31")
inspect(i8_0.sub(i8_31), content="i8 -31")
let i16_5 = ctx.getConstInt16(5)
let i16_72 = ctx.getConstInt16(72)
inspect(i16_72.sub(i16_5), content="i16 67")
let i32_m7 = ctx.getConstInt32(-7)
let i32_81 = ctx.getConstInt32(81)
inspect(i32_m7.sub(i32_81), content="i32 -88")
let i64_16 = ctx.getConstInt64(16)
let i64_m33 = ctx.getConstInt64(-33)
inspect(i64_16.sub(i64_m33), content="i64 49")
assert_true((try! i32_81.sub(i64_16)) is Err(_))
}

#
ConstantInt::trunc

fn ConstantInt::trunc(self : ConstantInt, dst_ty : &IntegerType) -> ConstantInt raise LLVMValueError

Truncate this ConstantInt to a smaller integer type, useful in constant folding.

Note: It will raise TruncCastInstTypeMismatch if the source type bit width is not greater than the destination type bit width.

test {
let ctx = Context::new()
let i32_255 = ctx.getConstInt32(255)
let i8_255 = i32_255.trunc(ctx.getInt8Ty())
inspect(i8_255, content="i8 -1")
let i64_0xFFFF = ctx.getConstInt64(0xFFFF)
let i16_0xFFFF = i64_0xFFFF.trunc(ctx.getInt16Ty())
inspect(i16_0xFFFF, content="i16 -1")
let i32_12345 = ctx.getConstInt32(12345)
let i16_12345 = i32_12345.trunc(ctx.getInt16Ty())
inspect(i16_12345, content="i16 12345")

// Test error case: cannot truncate to larger type
let i8_val = ctx.getConstInt8(42)
assert_true((try! i8_val.trunc(ctx.getInt32Ty())) is Err(_))
}

#
ConstantInt::udiv

fn ConstantInt::udiv(self : ConstantInt, other : ConstantInt) -> ConstantInt raise LLVMValueError

Unsigned divide two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same. It will raise DivisionByZeroError if other is zero.

test {
let ctx = Context::new()

// Test case 1: i8 unsigned division
// 200u8 / 10u8 = 20u8. ConstantInt stores 20L.
let i8_200 = ctx.getConstInt8(200) // Internally stored as -56L
let i8_10 = ctx.getConstInt8(10)
inspect(i8_200.udiv(i8_10), content="i8 20")

// Test case 2: i8 unsigned division with -1 (255u8)
// 255u8 / 2u8 = 127u8. ConstantInt stores 127L.
let i8_m1 = ctx.getConstInt8(-1) // Internally stored as -1L, represents 255u8
let i8_2 = ctx.getConstInt8(2)
inspect(i8_m1.udiv(i8_2), content="i8 127")

// Test case 3: i32 unsigned division
// 2147483647u / 2u = 1073741823u.
let i32_max_signed = ctx.getConstInt32(@int.max_value) // 2147483647
let i32_2 = ctx.getConstInt32(2)
inspect(i32_max_signed.udiv(i32_2), content="i32 1073741823")

// Test case 4: i64 unsigned division (UInt64.max_value / 2)
// (-1L as UInt64) / 2 = (2^64 - 1) / 2 = 2^63 - 1 (which is Int64.max_value)
let i64_m1 = ctx.getConstInt64(-1L)
let i64_2 = ctx.getConstInt64(2L)
inspect(i64_m1.udiv(i64_2), content="i64 9223372036854775807")

// Test case 5: Type mismatch
let i8_5 = ctx.getConstInt8(5)
let i16_2 = ctx.getConstInt16(2)
assert_true((try! i8_5.udiv(i16_2)) is Err(_))

// Test case 6: Division by zero
let i8_0 = ctx.getConstInt8(0)
assert_true((try! i8_5.udiv(i8_0)) is Err(_))

// Test case 7: i1 unsigned division
let i1_true = ctx.getConstTrue()
let i1_false = ctx.getConstFalse()
inspect(i1_true.udiv(i1_true), content="i1 true") // 1u / 1u = 1u
inspect(i1_false.udiv(i1_true), content="i1 false") // 0u / 1u = 0u
}

#
ConstantInt::uitofp

fn ConstantInt::uitofp(self : ConstantInt, dst_ty : &FPType) -> ConstantFP

Convert this ConstantInt to a floating-point type (unsigned interpretation), useful in constant folding.

Note: It will raise UIToFPInstTypeMismatch if the source is not an integer type.

test {
let ctx = Context::new()
let i32_255 = ctx.getConstInt32(255)
let f32_255 = i32_255.uitofp(ctx.getFloatTy())
assert_eq(f32_255.getValue(), 255.0)
let i8_m1 = ctx.getConstInt8(-1) // 255 as unsigned
let f64_255 = i8_m1.uitofp(ctx.getDoubleTy())
assert_eq(f64_255.getValue(), 255.0)
let i64_0 = ctx.getConstInt64(0)
let f32_0 = i64_0.uitofp(ctx.getFloatTy())
assert_eq(f32_0.getValue(), 0.0)
}

#
ConstantInt::xor

Bitwise XOR two ConstantInt, useful in constant folding.

Note: It will raise TypeMismatchForBinaryOp if the types of two ConstantInt are not the same.

test {
let ctx = Context::new()
let i8_6 = ctx.getConstInt8(6) // 00000110
let i8_3 = ctx.getConstInt8(3) // 00000011
inspect(i8_6.xor(i8_3), content="i8 5") // 00000101
let i16_val = ctx.getConstInt16(0xAA) // ...10101010
let i16_m1 = ctx.getConstInt16(-1) // ...11111111
inspect(i16_val.xor(i16_m1), content="i16 -171") // ...01010101 (which is -0xAB or -171 for i16)
let i32_pattern = ctx.getConstInt32(0x0F0F0F0F)
let i32_self_xor = i32_pattern.xor(i32_pattern)
inspect(i32_self_xor, content="i32 0")
let i64_val = ctx.getConstInt64(12345L)
let i64_0 = ctx.getConstInt64(0L)
inspect(i64_val.xor(i64_0), content="i64 12345")
}

#
ConstantInt::zext

fn ConstantInt::zext(self : ConstantInt, dst_ty : &IntegerType) -> ConstantInt raise LLVMValueError

Zero extend this ConstantInt to a larger integer type, useful in constant folding.

Note: It will raise ZExtCastInstTypeMismatch if the source type bit width is not less than the destination type bit width.

test {
let ctx = Context::new()
let i8_255 = ctx.getConstInt8(255) // -1 as signed, 255 as unsigned
let i32_255 = i8_255.zext(ctx.getInt32Ty())
inspect(i32_255, content="i32 255")
let i1_true = ctx.getConstTrue()
let i8_true = i1_true.zext(ctx.getInt8Ty())
inspect(i8_true, content="i8 1")
let i16_42 = ctx.getConstInt16(42)
let i64_42 = i16_42.zext(ctx.getInt64Ty())
inspect(i64_42, content="i64 42")

// Test error case: cannot zext to smaller type
let i32_val = ctx.getConstInt32(42)
assert_true((try! i32_val.zext(ctx.getInt8Ty())) is Err(_))
}

#
ConstantPointerNull

pub struct ConstantPointerNull {
uid : UInt64
vty : PointerType
}

#
ConstantString

pub struct ConstantString {
uid : UInt64
vty : ArrayType
data : String
}

#
ConstantStruct

pub struct ConstantStruct {
uid : UInt64
vty : StructType
elements : Array[&Constant]
}

ConstantStruct

Represents a constant struct value in LLVM IR.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let sty = ctx.getStructType([i32ty, f32ty])
let i32_val = ctx.getConstInt32(42)
let f32_val = ctx.getConstFloat(3.14)
let struct_val = ConstantStruct::new(sty, [i32_val, f32_val])
inspect(
struct_val,
content="{ i32, float } { i32 42, float 0x40091EB860000000 }",
)
}

#
ConstantStruct::extractValue

fn ConstantStruct::extractValue(self : ConstantStruct, indices : ArrayView[Int]) -> &Constant?

Extract a value from this constant struct using a sequence of indices.

This is equivalent to LLVM's extractvalue instruction for constant structs. The indices specify a path through nested aggregate types.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let sty = ctx.getStructType([i32ty, f32ty])
let i32_val = ctx.getConstInt32(42)
let f32_val = ctx.getConstFloat(3.14)
let struct_val = ConstantStruct::new(sty, [i32_val, f32_val])
inspect(struct_val.extractValue([0]), content="Some(i32 42)")
inspect(
struct_val.extractValue([1]),
content="Some(float 0x40091EB860000000)",
)
inspect(struct_val.extractValue([2]), content="None") // Out of bounds
}

#
ConstantStruct::getElement

fn ConstantStruct::getElement(self : ConstantStruct, index : Int) -> &Constant?

Get the element at the specified index.

#
ConstantStruct::getElements

fn ConstantStruct::getElements(self : ConstantStruct) -> Array[&Constant]

Get the elements of this constant struct.

#
ConstantStruct::insertValue

fn ConstantStruct::insertValue(self : ConstantStruct, indices : ArrayView[Int], value : &Constant) -> ConstantStruct?

Insert a value into this constant struct using a sequence of indices.

This is equivalent to LLVM's insertvalue instruction for constant structs. Returns a new ConstantStruct with the value inserted at the specified path.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let sty = ctx.getStructType([i32ty, f32ty])
let i32_val = ctx.getConstInt32(42)
let f32_val = ctx.getConstFloat(3.14)
let struct_val = ConstantStruct::new(sty, [i32_val, f32_val])

// Insert new value at index 0
let new_i32_val = ctx.getConstInt32(100)
guard struct_val.insertValue([0], new_i32_val) is Some(new_struct)

// Verify the new value was inserted
assert_true(new_struct.extractValue([0]) is Some(_))
}
// TODO: not correct

#
ConstantStruct::new

fn ConstantStruct::new(vty : StructType, elements : Array[&Constant]) -> ConstantStruct

#
ConstantVector

pub struct ConstantVector {
uid : UInt64
vty : VectorType
data :
Either
[Array[&Constant], NumberArrayEnum]
}

#
Context

pub struct Context {
key : UInt
// private fields
}

impl Eq for Context
impl Hash for Context

#
Context::addModule

fn Context::addModule(self : Context, moduleID : String, source_file? : String?) -> Module

#
Context::createBuilder

fn Context::createBuilder(self : Context) -> IRBuilder

#
Context::getArrayType

fn Context::getArrayType(self : Context, elementType : &Type, numElements : Int) -> ArrayType raise LLVMTypeError

Create an array type in the context.

This is different with the method of creating array type in LLVM. In LLVM, usually use ArrayType::get to create an array type.

In Moonbit Aether framework, we use Context::getArrayType to create an array type.

  • See LLVM: ArrayType::get.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let arrty = ctx.getArrayType(i32ty, 16)
inspect(arrty, content="[16 x i32]")
inspect(arrty.getElementType(), content="i32")
assert_eq(arrty.getElementCount(), 16)
}

#
Context::getBFloatTy

fn Context::getBFloatTy(self : Context) -> BFloatType

Get the bfloat type from context.

  • See LLVM: Type::getBFloatTy.

test {
let ctx = Context::new()
let bfloat_ty = ctx.getBFloatTy()
inspect(bfloat_ty, content="bfloat")
}

#
Context::getConstArray

fn Context::getConstArray(self : Context, elementType : &Type, data : Array[&Constant]) -> ConstantArray

#
Context::getConstBool

fn Context::getConstBool(self : Context, b : Bool) -> ConstantInt

Create a constant with bool type.

  • See LLVM: ConstantInt::get.

test {
let ctx = Context::new()
inspect(ctx.getConstBool(true), content="i1 true")
inspect(ctx.getConstBool(false), content="i1 false")
}

#
Context::getConstDouble

fn Context::getConstDouble(self : Context, value : Double) -> ConstantFP

Create a constant with double type.

  • See LLVM: ConstantFP::get.

test {
let ctx = Context::new()
let one = ctx.getConstDouble(1.0)
let two = ctx.getConstDouble(2.0)
inspect(one, content="double 0x3FF0000000000000")
inspect(two, content="double 0x4000000000000000")
}

#
Context::getConstDoubleArray

fn Context::getConstDoubleArray(self : Context, data : Array[Double]) -> ConstantArray

Create a constant array with double type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[Double] = [1.0, 2.0]
let arr = ctx.getConstDoubleArray(data)
inspect(
arr,
content="[2 x double] [double 0x3FF0000000000000, double 0x4000000000000000]",
)
}

#
Context::getConstDoubleVector

fn Context::getConstDoubleVector(self : Context, data : Array[Double]) -> ConstantVector

Create a constant array with double type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[Double] = [1.0, 2.0]
let arr = ctx.getConstDoubleVector(data)
inspect(
arr,
content="<2 x double> <double 0x3FF0000000000000, double 0x4000000000000000>",
)
}

#
Context::getConstFalse

fn Context::getConstFalse(self : Context) -> ConstantInt

Create a constant with bool type, false value.

  • See LLVM: ConstantInt::getFalse.

test {
let ctx = Context::new()
inspect(ctx.getConstFalse(), content="i1 false")
}

#
Context::getConstFloat

fn Context::getConstFloat(self : Context, value : Float) -> ConstantFP

Create a constant with float type.

  • See LLVM: ConstantFP::get.

test {
let ctx = Context::new()
let one = ctx.getConstFloat(1.0)
let two = ctx.getConstFloat(2.0)
inspect(one, content="float 0x3FF0000000000000")
inspect(two, content="float 0x4000000000000000")
}

#
Context::getConstFloatArray

fn Context::getConstFloatArray(self : Context, data : Array[Float]) -> ConstantArray

Create a constant array with float type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[Float] = [1.0, 2.0]
let arr = ctx.getConstFloatArray(data)
inspect(
arr,
content="[2 x float] [float 0x3FF0000000000000, float 0x4000000000000000]",
)
}

#
Context::getConstFloatVector

fn Context::getConstFloatVector(self : Context, data : Array[Float]) -> ConstantVector

Create a constant array with float type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[Float] = [1.0, 2.0]
let arr = ctx.getConstFloatVector(data)
inspect(
arr,
content="<2 x float> <float 0x3FF0000000000000, float 0x4000000000000000>",
)
}

#
Context::getConstInfDouble

fn Context::getConstInfDouble(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant Infinity with double type.

  • See LLVM: ConstantFP::getInfinity.

Parameter:

  • isNegative: If true, create a negative Infinity constant.

test {
let ctx = Context::new()
let inf = ctx.getConstInfDouble()
let neg_inf = ctx.getConstInfDouble(isNegative=true)
inspect(inf, content="double 0x7FF0000000000000")
inspect(neg_inf, content="double 0xFFF0000000000000")
}

#
Context::getConstInfFloat

fn Context::getConstInfFloat(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant Infinity with float type.

  • See LLVM: ConstantFP::getInfinity.

Parameter:

  • isNegative: If true, create a negative Infinity constant.

test {
let ctx = Context::new()
let inf = ctx.getConstInfFloat()
let neg_inf = ctx.getConstInfFloat(isNegative=true)
inspect(inf, content="float 0x7FF0000000000000")
inspect(neg_inf, content="float 0xFFF0000000000000")
}

#
Context::getConstInt16

fn Context::getConstInt16(self : Context, value : Int16) -> ConstantInt

Create a constant with int16 type.

  • See LLVM: ConstantInt::get.

test {
let ctx = Context::new()
inspect(ctx.getConstInt16(0), content="i16 0")
inspect(ctx.getConstInt16(1), content="i16 1")
inspect(ctx.getConstInt16(-1), content="i16 -1")
}

#
Context::getConstInt16Array

fn Context::getConstInt16Array(self : Context, data : Array[Int16]) -> ConstantArray

Create a constant array with int16 type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[Int16] = [42, 63, 77, 89]
let arr = ctx.getConstInt16Array(data)
inspect(arr, content="[4 x i16] [i16 42, i16 63, i16 77, i16 89]")
}

#
Context::getConstInt16Vector

fn Context::getConstInt16Vector(self : Context, data : Array[Int16]) -> ConstantVector

Create a constant vector with int16 type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[Int16] = [42, 63, 77, 89]
let arr = ctx.getConstInt16Vector(data)
inspect(arr, content="<4 x i16> <i16 42, i16 63, i16 77, i16 89>")
}

#
Context::getConstInt32

fn Context::getConstInt32(self : Context, value : Int) -> ConstantInt

Create a constant with int32 type.

  • See LLVM: ConstantInt::get.

test {
let ctx = Context::new()
inspect(ctx.getConstInt32(0), content="i32 0")
inspect(ctx.getConstInt32(1), content="i32 1")
inspect(ctx.getConstInt32(-1), content="i32 -1")
}

#
Context::getConstInt32Array

fn Context::getConstInt32Array(self : Context, data : Array[Int]) -> ConstantArray

Create a constant array with int32 type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[Int] = [42, 63, 77, 89]
let arr = ctx.getConstInt32Array(data)
inspect(arr, content="[4 x i32] [i32 42, i32 63, i32 77, i32 89]")
}

#
Context::getConstInt32Vector

fn Context::getConstInt32Vector(self : Context, data : Array[Int]) -> ConstantVector

Create a constant vector with int32 type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[Int] = [42, 63, 77, 89]
let arr = ctx.getConstInt32Vector(data)
inspect(arr, content="<4 x i32> <i32 42, i32 63, i32 77, i32 89>")
}

#
Context::getConstInt64

fn Context::getConstInt64(self : Context, value : Int64) -> ConstantInt

Create a constant with int64 type.

  • See LLVM: ConstantInt::get.

test {
let ctx = Context::new()
inspect(ctx.getConstInt64(0), content="i64 0")
inspect(ctx.getConstInt64(1), content="i64 1")
inspect(ctx.getConstInt64(-1), content="i64 -1")
}

#
Context::getConstInt64Array

fn Context::getConstInt64Array(self : Context, data : Array[Int64]) -> ConstantArray

Create a constant array with int32 type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[Int64] = [42, 63, 77, 89]
let arr = ctx.getConstInt64Array(data)
inspect(arr, content="[4 x i64] [i64 42, i64 63, i64 77, i64 89]")
}

#
Context::getConstInt64Vector

fn Context::getConstInt64Vector(self : Context, data : Array[Int64]) -> ConstantVector

Create a constant array with int32 type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[Int64] = [42, 63, 77, 89]
let arr = ctx.getConstInt64Vector(data)
inspect(arr, content="<4 x i64> <i64 42, i64 63, i64 77, i64 89>")
}

#
Context::getConstInt8

fn Context::getConstInt8(self : Context, value : Int) -> ConstantInt

Create a constant with int8 type.

  • See LLVM: ConstantInt::get.

test {
let ctx = Context::new()
inspect(ctx.getConstInt8(0), content="i8 0")
inspect(ctx.getConstInt8(1), content="i8 1")
inspect(ctx.getConstInt8(-1), content="i8 -1")
}

#
Context::getConstInt8Array

fn Context::getConstInt8Array(self : Context, data : Array[Int]) -> ConstantArray

Create a constant array with int8 type.

  • See LLVM: ConstantDataArray::get.

Note:

  • Core does not support int8 currently, hence the type of parameter data is Array[Int].

test {
let ctx = Context::new()
let data : Array[Int] = [42, 63, 77, 89]
let arr = ctx.getConstInt8Array(data)
inspect(arr, content="[4 x i8] [i8 42, i8 63, i8 77, i8 89]")
}

#
Context::getConstInt8Vector

fn Context::getConstInt8Vector(self : Context, data : Array[Int]) -> ConstantVector

Create a constant vector with int8 type.

  • See LLVM: ConstantDataVector::get.

Note:

  • Core does not support int8 currently, hence the type of parameter data is Array[Int].

test {
let ctx = Context::new()
let data : Array[Int] = [42, 63, 77, 89]
let arr = ctx.getConstInt8Vector(data)
inspect(arr, content="<4 x i8> <i8 42, i8 63, i8 77, i8 89>")
}

#
Context::getConstNaNDouble

fn Context::getConstNaNDouble(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant NaN with double type.

  • See LLVM: ConstantFP::getNaN.

Parameter:

  • isNegative: If true, create a negative NaN constant.

test {
let ctx = Context::new()
let nan = ctx.getConstNaNDouble()
let neg_nan = ctx.getConstNaNDouble(isNegative=true)
inspect(nan, content="double 0x7FF8000000000000")
inspect(neg_nan, content="double 0xFFF8000000000000")
}

#
Context::getConstNaNFloat

fn Context::getConstNaNFloat(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant NaN with double type.

  • See LLVM: ConstantFP::getZero.

Parameter:

  • isNegative: If true, create a negative zero constant.

test {
let ctx = Context::new()
let nan = ctx.getConstNaNDouble()
let neg_nan = ctx.getConstNaNDouble(isNegative=true)
inspect(nan, content="double 0x7FF8000000000000")
inspect(neg_nan, content="double 0xFFF8000000000000")
}

#
Context::getConstOne

fn Context::getConstOne(self : Context, ty : &Type) -> &Constant raise LLVMValueError

#
Context::getConstPointerNull

fn Context::getConstPointerNull(self : Context, ty : &Type, addressSpace? : UInt) -> ConstantPointerNull

#
Context::getConstQNaNDouble

fn Context::getConstQNaNDouble(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant Quiet NaN with double type.

  • See LLVM: ConstantFP::getQNaN.

Parameter:

  • isNegative: If true, create a negative NaN constant.

test {
let ctx = Context::new()
let nan = ctx.getConstQNaNDouble()
let neg_nan = ctx.getConstQNaNDouble(isNegative=true)
inspect(nan, content="double 0x7FF8000000000000")
inspect(neg_nan, content="double 0xFFF8000000000000")
}

#
Context::getConstQNaNFloat

fn Context::getConstQNaNFloat(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant Quiet NaN with float type.

  • See LLVM: ConstantFP::getQNaN.

Parameter:

  • isNegative: If true, create a negative NaN constant.

test {
let ctx = Context::new()
let nan = ctx.getConstQNaNFloat()
let neg_nan = ctx.getConstQNaNFloat(isNegative=true)
inspect(nan, content="float 0x7FF8000000000000")
inspect(neg_nan, content="float 0xFFF8000000000000")
}

#
Context::getConstSNaNDouble

fn Context::getConstSNaNDouble(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant Signaling NaN with double type.

  • See LLVM: ConstantFP::getSNaN.

Parameter:

  • isNegative: If true, create a negative NaN constant.

test {
let ctx = Context::new()
let nan = ctx.getConstSNaNDouble()
let neg_nan = ctx.getConstSNaNDouble(isNegative=true)
inspect(nan, content="double 0x7FF4000000000000")
inspect(neg_nan, content="double 0xFFF4000000000000")
}

#
Context::getConstSNaNFloat

fn Context::getConstSNaNFloat(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant Signaling NaN with float type.

  • See LLVM: ConstantFP::getSNaN.

Parameter:

  • isNegative: If true, create a negative NaN constant.

test {
let ctx = Context::new()
let nan = ctx.getConstSNaNFloat()
let neg_nan = ctx.getConstSNaNFloat(isNegative=true)
inspect(nan, content="float 0x7FF4000000000000")
inspect(neg_nan, content="float 0xFFF4000000000000")
}

#
Context::getConstTrue

fn Context::getConstTrue(self : Context) -> ConstantInt

Create a constant with bool type, true value.

  • See LLVM: ConstantInt::getTrue.

test {
let ctx = Context::new()
inspect(ctx.getConstTrue(), content="i1 true")
}

#
Context::getConstUInt16Array

fn Context::getConstUInt16Array(self : Context, data : Array[UInt16]) -> ConstantArray

Create a constant array with uint16 type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[UInt16] = [42, 63, 77, 89]
let arr = ctx.getConstUInt16Array(data)
inspect(arr, content="[4 x i16] [i16 42, i16 63, i16 77, i16 89]")
}

#
Context::getConstUInt16Vector

fn Context::getConstUInt16Vector(self : Context, data : Array[UInt16]) -> ConstantVector

Create a constant array with uint16 type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[UInt16] = [42, 63, 77, 89]
let arr = ctx.getConstUInt16Vector(data)
inspect(arr, content="<4 x i16> <i16 42, i16 63, i16 77, i16 89>")
}

#
Context::getConstUInt32Array

fn Context::getConstUInt32Array(self : Context, data : Array[UInt]) -> ConstantArray

Create a constant array with uint32 type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[UInt] = [42, 63, 77, 89]
let arr = ctx.getConstUInt32Array(data)
inspect(arr, content="[4 x i32] [i32 42, i32 63, i32 77, i32 89]")
}

#
Context::getConstUInt32Vector

fn Context::getConstUInt32Vector(self : Context, data : Array[UInt]) -> ConstantVector

Create a constant array with uint32 type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[UInt] = [42, 63, 77, 89]
let arr = ctx.getConstUInt32Vector(data)
inspect(arr, content="<4 x i32> <i32 42, i32 63, i32 77, i32 89>")
}

#
Context::getConstUInt64Array

fn Context::getConstUInt64Array(self : Context, data : Array[UInt64]) -> ConstantArray

Create a constant array with uint64 type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[UInt64] = [42, 63, 77, 89]
let arr = ctx.getConstUInt64Array(data)
inspect(arr, content="[4 x i64] [i64 42, i64 63, i64 77, i64 89]")
}

#
Context::getConstUInt64Vector

fn Context::getConstUInt64Vector(self : Context, data : Array[UInt64]) -> ConstantVector

Create a constant array with uint64 type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[UInt64] = [42, 63, 77, 89]
let arr = ctx.getConstUInt64Vector(data)
inspect(arr, content="<4 x i64> <i64 42, i64 63, i64 77, i64 89>")
}

#
Context::getConstUInt8Array

fn Context::getConstUInt8Array(self : Context, data : Array[Byte]) -> ConstantArray

Create a constant array with uint8 type.

  • See LLVM: ConstantDataArray::get.

test {
let ctx = Context::new()
let data : Array[Byte] = [42, 63, 77, 89]
let arr = ctx.getConstUInt8Array(data)
inspect(arr, content="[4 x i8] [i8 42, i8 63, i8 77, i8 89]")
}

#
Context::getConstUInt8Vector

fn Context::getConstUInt8Vector(self : Context, data : Array[Byte]) -> ConstantVector

Create a constant array with uint8 type.

  • See LLVM: ConstantDataVector::get.

test {
let ctx = Context::new()
let data : Array[Byte] = [42, 63, 77, 89]
let arr = ctx.getConstUInt8Vector(data)
inspect(arr, content="<4 x i8> <i8 42, i8 63, i8 77, i8 89>")
}

#
Context::getConstZero

fn Context::getConstZero(self : Context, ty : &Type) -> &Constant raise LLVMValueError

Create a constant zero value (null value) of a given type.

TODO: wait compiler bug fixed.

let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let zero_i32 = ctx.getConstZero(i32ty)
inspect(zero_i32, content="i32 0")

#
Context::getConstZeroDouble

fn Context::getConstZeroDouble(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant zero with double type.

  • See LLVM: ConstantFP::getZero.

Parameter:

  • isNegative: If true, create a negative zero constant.

test {
let ctx = Context::new()
let zero = ctx.getConstZeroDouble()
let neg_zero = ctx.getConstZeroDouble(isNegative=true)
inspect(zero, content="double 0x0")
inspect(neg_zero, content="double 0x8000000000000000")
}

#
Context::getConstZeroFloat

fn Context::getConstZeroFloat(self : Context, isNegative? : Bool) -> ConstantFP

Create a constant zero with float type.

  • See LLVM: ConstantFP::getZero.

Parameter:

  • isNegative: If true, create a negative zero constant.

test {
let ctx = Context::new()
let zero = ctx.getConstZeroFloat()
let neg_zero = ctx.getConstZeroFloat(isNegative=true)
inspect(zero, content="float 0x0")
inspect(neg_zero, content="float 0x8000000000000000")
}

#
Context::getDoubleTy

fn Context::getDoubleTy(self : Context) -> DoubleType

Get the double type from context.

  • See LLVM: Type::getDoubleTy.

test {
let ctx = Context::new()
let doubletype = ctx.getDoubleTy()
inspect(doubletype, content="double")
}

#
Context::getFP128Ty

fn Context::getFP128Ty(self : Context) -> FP128Type

Get the fp128 type from context.

  • See LLVM: Type::getFP128Ty.

test {
let ctx = Context::new()
let fp128ty = ctx.getFP128Ty()
inspect(fp128ty, content="fp128")
}

#
Context::getFixedVectorType

fn Context::getFixedVectorType(self : Context, elementType : &Type, elementQuantity : Int) -> VectorType raise LLVMTypeError

Create a fixed length vector type in the context.

  • See LLVM: VectorType::get.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let fixedVecTy = ctx.getFixedVectorType(i32ty, 32)
inspect(fixedVecTy, content="<32 x i32>")
}

#
Context::getFloatTy

fn Context::getFloatTy(self : Context) -> FloatType

Get the float type from context.

  • See LLVM: Type::getFloatTy.

test {
let ctx = Context::new()
let f32ty = ctx.getFloatTy()
inspect(f32ty, content="float")
}

#
Context::getFunctionType

fn Context::getFunctionType(self : Context, returnType : &Type, paramTypes : Array[&Type], isVarArg? : Bool) -> FunctionType raise LLVMTypeError

Create a function type.

This is different with the method of creating function type in LLVM. In LLVM, usually use FunctionType::get to create a function type.

In Moonbit Aether framework, we use Context::getFunctionType to create a function type.

  • See LLVM: FunctionType::get.

test {
let ctx = Context::new()
let voidty = ctx.getVoidTy()
let i32ty = ctx.getInt32Ty()
let f64ty = ctx.getDoubleTy()
let fty = ctx.getFunctionType(voidty, [i32ty, f64ty])
inspect(fty, content="void (i32, double)")
}

#
Context::getHalfTy

fn Context::getHalfTy(self : Context) -> HalfType

Get the half type from context.

  • See LLVM: Type::getHalfTy.

test {
let ctx = Context::new()
let half_ty = ctx.getHalfTy()
inspect(half_ty, content="half")
}

#
Context::getInt16Ty

fn Context::getInt16Ty(self : Context) -> Int16Type

Get the integer type with 16 bits from context.

#
Context::getInt1Ty

fn Context::getInt1Ty(self : Context) -> Int1Type

Get the integer type with 1 bit from context.

#
Context::getInt32Ty

fn Context::getInt32Ty(self : Context) -> Int32Type

Get the integer type with 32 bits from context.

#
Context::getInt64Ty

fn Context::getInt64Ty(self : Context) -> Int64Type

Get the integer type with 64 bits from context.

#
Context::getInt8Ty

fn Context::getInt8Ty(self : Context) -> Int8Type

Get the integer type with 8 bits from context.

#
Context::getLabelTy

fn Context::getLabelTy(self : Context) -> LabelType

Get the label type from context.

#
Context::getMDString

fn Context::getMDString(self : Context, str : String) -> MDString

#
Context::getMetadataTy

fn Context::getMetadataTy(self : Context) -> MetadataType

Get the metadata type from context.

#
Context::getPtrTy

fn Context::getPtrTy(self : Context, addressSpace? : AddressSpace) -> PointerType

Get the Pointer type from context.

  • See LLVM: PointerType::get.

Note:

After LLVM17, typed pointer has been deprecated. Therefore in Moonbit Aether framework, all pointer type is opaque.

test {
let ctx = Context::new()
inspect(ctx.getPtrTy(), content="ptr")
let addressSpace = AddressSpace::new(1)
inspect(ctx.getPtrTy(addressSpace~), content="ptr")
}

#
Context::getScalableVectorType

fn Context::getScalableVectorType(self : Context, elementType : &Type, elementQuantity : Int) -> ScalableVectorType raise LLVMTypeError

Create a scalable vector type in the context.

  • See LLVM: ScalableVectorType::get.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let scalableVecTy = ctx.getScalableVectorType(i32ty, 16)
inspect(scalableVecTy, content="<vscale x 16 x i32>")
}

#
Context::getStructType

fn Context::getStructType(self : Context, elements : Array[&Type], name? : String, isPacked? : Bool) -> StructType raise LLVMTypeError

Create a struct type in the context.

This is different with the method of creating struct type in LLVM. In LLVM, usually use StructType::create to create a struct type.

In Moonbit Aether framework, we use Context::getStructType to create a struct type.

  • See LLVM: StructType::create.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let f64ty = ctx.getDoubleTy()
let sty = ctx.getStructType([i32ty, f32ty, f64ty], name="foo")
inspect(sty.full_info(), content="%foo = type { i32, float, double }")

// Cannot create a ananymous struct type with empty elements.
assert_true((try! ctx.getStructType([])) is Err(_))

// Cannot create a struct which has same name with other struct.
// the `foo` struct is already created.
assert_true((try! ctx.getStructType([], name="foo")) is Err(_))
}

#
Context::getStructTypeByName

fn Context::getStructTypeByName(self : Context, name : String) -> StructType?

Search a named struct type in the context.

LLVM Cpp version has no this method, since llvm-cpp allow duplicated struct type names.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let _ = ctx.getStructType([i32ty, f32ty], name="foo")
let sty = ctx.getStructTypeByName("foo").unwrap()
inspect(sty.full_info(), content="%foo = type { i32, float }")
}

#
Context::getTokenTy

fn Context::getTokenTy(self : Context) -> TokenType

Get the token type from context.

  • See LLVM: Type::getTokenTy.

test {
let ctx = Context::new()
let tokenty = ctx.getTokenTy()
inspect(tokenty, content="token")
}

#
Context::getVoidTy

fn Context::getVoidTy(self : Context) -> VoidType

Get the void type from context.

  • See LLVM: Type::getVoidTy.

test {
let ctx = Context::new()
let voidty = ctx.getVoidTy()
inspect(voidty, content="void")
}

#
Context::new

fn Context::new() -> Context

#
DLLStorageClass

pub(all) enum DLLStorageClass {
DefaultDLLStorageClass
DLLImportStorageClass
DLLExportStorageClass
}

#
DataLayout

pub struct DataLayout {
endian : Endian
}

#
DataLayout::getArrayTypeAllocSizeInBits

fn DataLayout::getArrayTypeAllocSizeInBits(self : DataLayout, ty : ArrayType) -> Int

#
DataLayout::getEndian

fn DataLayout::getEndian(self : DataLayout) -> Endian

#
DataLayout::getStructTypeAllocSizeInBits

fn DataLayout::getStructTypeAllocSizeInBits(self : DataLayout, ty : StructType) -> Int

#
DataLayout::getStructTypeOffset

fn DataLayout::getStructTypeOffset(self : DataLayout, sty : StructType, index : Int) -> Int

Get the byte offset of a specific field in a struct type.

Note:

This function calculates the byte offset from the beginning of the struct to the specified field index. The offset includes proper alignment padding as required by the target's ABI. For packed structs, no alignment padding is added between fields.

Parameters:
  • sty: The struct type to analyze
  • index: The zero-based index of the field (0 = first field, 1 = second field, etc.)

Return Value:
  • Returns the byte offset of the field at the specified index
  • Returns 0 for invalid indices (negative or out of bounds)
  • Returns 0 for empty or opaque structs

Alignment Behavior:
  • Non-packed structs: Each field is aligned to its natural alignment boundary
  • Packed structs: Fields are placed consecutively with no alignment padding

Examples:

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let datalayout = mod.getDataLayout()
let i8ty = ctx.getInt8Ty()
let i32ty = ctx.getInt32Ty()
let i64ty = ctx.getInt64Ty()

// Non-packed struct: { i8, i32, i64 }
let normal_struct = ctx.getStructType([i8ty, i32ty, i64ty])
assert_eq(datalayout.getStructTypeOffset(normal_struct, 0), 0) // i8
assert_eq(datalayout.getStructTypeOffset(normal_struct, 1), 4) // i32, aligned
assert_eq(datalayout.getStructTypeOffset(normal_struct, 2), 8) // i64, aligned

// Packed struct: packed { i8, i32, i64 }
let packed_struct = ctx.getStructType([i8ty, i32ty, i64ty], isPacked=true)
assert_eq(datalayout.getStructTypeOffset(packed_struct, 0), 0) // i8
assert_eq(datalayout.getStructTypeOffset(packed_struct, 1), 1) // i32, no padding
assert_eq(datalayout.getStructTypeOffset(packed_struct, 2), 5) // i64, no padding

// Invalid indices return 0
assert_eq(datalayout.getStructTypeOffset(normal_struct, -1), 0)
assert_eq(datalayout.getStructTypeOffset(normal_struct, 10), 0)
}

#
DataLayout::getTypeAllocSize

fn DataLayout::getTypeAllocSize(self : DataLayout, ty : &Type) -> Int

Get the allocation size in bytes for a type.

Note:

This function returns the number of bytes that would be allocated for this type, including any padding required for alignment. This is the size that would be returned by sizeof() in C for the corresponding type.

Supported Types:
  • Primitive types: Int1, Int8, Int16, Int32, Int64, Half, BFloat, Float, Double
  • Pointer types: All pointer types (8 bytes on 64-bit architectures)
  • Array types: Element size multiplied by element count
  • Struct types: Sum of member sizes with proper alignment padding

Examples:

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let datalayout = mod.getDataLayout()

// Basic types
let i32ty = ctx.getInt32Ty()
assert_eq(datalayout.getTypeAllocSize(i32ty), 4)

// Array types
let arrty = ctx.getArrayType(i32ty, 10)
assert_eq(datalayout.getTypeAllocSize(arrty), 40) // 4 * 10

// Struct types with alignment
let struct_ty = ctx.getStructType([ctx.getInt8Ty(), i32ty])
assert_eq(datalayout.getTypeAllocSize(struct_ty), 8) // 1 + 3 padding + 4
}

#
DataLayout::getTypeAllocSizeInBits

fn DataLayout::getTypeAllocSizeInBits(self : DataLayout, ty : &Type) -> Int

#
DoubleArray

pub type DoubleArray Array[Double]

impl Eq for DoubleArray
impl Hash for DoubleArray
impl Show for DoubleArray

#
DoubleArray::from

fn DoubleArray::from(data : Array[Double]) -> DoubleArray

#
DoubleArray::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn DoubleArray::inner(self : DoubleArray) -> Array[Double]
Convert newtype to its underlying type, automatically derived.

#
DoubleArray::iter

fn DoubleArray::iter(self : DoubleArray) -> Iter[Double]

#
DoubleArray::length

fn DoubleArray::length(self : DoubleArray) -> Int

#
DoubleType

pub struct DoubleType {
ctx : Context
}

DoubleType
impl Type for DoubleType
impl Eq for DoubleType
impl Hash for DoubleType
impl Show for DoubleType

#
Endian

pub(all) enum Endian {
Little
Big
}

#
ExtractValueInst

pub struct ExtractValueInst {
uid : UInt64
vty : &Type
users : Array[&User]
name : String?
aggregate : &Value
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
indices : Array[Int]
}

ExtractValueInst represents an extractvalue instruction that extracts a value from an aggregate (struct or array) at the specified index.

Note:

Use IRBuilder::createExtractValue to create an ExtractValueInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let struct_ty = ctx.getStructType([i32_ty, i32_ty])
let fty = ctx.getFunctionType(i32_ty, [struct_ty])
let fval = mod.addFunction(fty, "extractvalue_demo")
let bb = fval.addBasicBlock(name="entry")
let aggregate = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let extract = builder.createExtractValue(aggregate, [0], name="field")
inspect(extract, content=" %field = extractvalue { i32, i32 } %0, 0")
assert_true(extract.asValueEnum() is ExtractValueInst(_))
}

#
ExtractValueInst::getAggregateOperand

fn ExtractValueInst::getAggregateOperand(self : ExtractValueInst) -> &Value

#
ExtractValueInst::getIndices

fn ExtractValueInst::getIndices(self : ExtractValueInst) -> Array[Int]

#
FCmpInst

pub struct FCmpInst {
uid : UInt64
vty : Int1Type
lhs : &Value
rhs : &Value
name : String?
parent : Function
users : Array[&User]
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
predicate : FloatPredicate
}

FCmpInst represents a floating-point comparison instruction that compares two floating-point values.

Note:

Use IRBuilder::createFCmp to create an FCmpInst.

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")
}
impl User for FCmpInst
impl Value for FCmpInst
impl Show for FCmpInst

#
FNegInst

pub struct FNegInst {
uid : UInt64
vty : &Type
users : Array[&User]
name : String?
operand : &Value
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
fast_math_flags :
Set
[FastMathFlag]
}

impl User for FNegInst
impl Value for FNegInst
impl Show for FNegInst

#
FNegInst::new

fn FNegInst::new(operand : &Value, parent : Function, name~ : String?, fast_math_flags :
Set
[FastMathFlag]) -> FNegInst

#
FP128Type

pub struct FP128Type {
ctx : Context
}

FP128Ty
impl FPType for FP128Type
impl Type for FP128Type
impl Eq for FP128Type
impl Hash for FP128Type
impl Show for FP128Type

#
FPTypeEnum

pub enum FPTypeEnum {
HalfType(HalfType)
BFloatType(BFloatType)
FloatType(FloatType)
DoubleType(DoubleType)
FP128Type(FP128Type)
}

impl Eq for FPTypeEnum
impl Show for FPTypeEnum

#
FPTypeEnum::asFPTypeClass

fn FPTypeEnum::asFPTypeClass(self : FPTypeEnum) -> &FPType

#
FPTypeEnum::asTypeClass

fn FPTypeEnum::asTypeClass(self : FPTypeEnum) -> &Type

#
FPTypeEnum::getBitWidth

fn FPTypeEnum::getBitWidth(self : FPTypeEnum) -> Int

#
FPTypeEnum::getFPMantissaWidth

fn FPTypeEnum::getFPMantissaWidth(self : FPTypeEnum) -> Int

#
FastMathFlag

pub(all) enum FastMathFlag {
AllowReassoc
NoNaNs
NoInfs
NoSignedZeros
AllowReciprocal
AllowContract
ApproxFunc
}

impl Eq for FastMathFlag

#
FloatArray

pub type FloatArray Array[Float]

impl Eq for FloatArray
impl Hash for FloatArray
impl Show for FloatArray

#
FloatArray::from

fn FloatArray::from(data : Array[Float]) -> FloatArray

#
FloatArray::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn FloatArray::inner(self : FloatArray) -> Array[Float]
Convert newtype to its underlying type, automatically derived.

#
FloatArray::iter

fn FloatArray::iter(self : FloatArray) -> Iter[Float]

#
FloatArray::length

fn FloatArray::length(self : FloatArray) -> Int

#
FloatPredicate

pub(all) enum FloatPredicate {
FALSE
OEQ
OGT
OGE
OLT
OLE
ONE
ORD
UNO
UEQ
UGT
UGE
ULT
ULE
UNE
TRUE
}

#
FloatType

pub struct FloatType {
ctx : Context
}

FloatType
impl FPType for FloatType
impl Type for FloatType
impl Eq for FloatType
impl Hash for FloatType
impl Show for FloatType

#
FloatingEnum

type FloatingEnum

impl Eq for FloatingEnum

#
FnAttr

pub(all) enum FnAttr {
AllocKind(Int)
AllocSize(Int)
AlwaysInline
Builtin
Cold
Convergent
Hot
DisableSanitizerInstrumentation
FnRetThunkExtern
HybridPatchable
InlineHint
JumpTable
Memory(Int)
MinSize
Naked
NoBuiltin
NoCallback
NoDivergenceSource
NoDuplicate
NoFree
NoImplicitFloat
NoInline
NonLazyBind
NoMerge
NoRecurse
NoRedZone
NoReturn
NoSync
NoCfCheck
NoProfile
SkipProfile
NoUnwind
NoSanitizeBounds
NoSanitizeCoverage
NullPointerIsValid
OptimizeForDebugging
OptForFuzzing
OptimizeForSize
OptimizeNone
Preallocated(&Type)
ReturnTwice
SafeStack
ShadowCallStack
StackAlignment(Int)
Speculatable
StackProtect
StackProtectReq
StackProtectStrong
StrictFP
SanitizeAddress
SanitizeThread
SanitizeType
SanitizeMemory
SanitizeHWAddress
SanitizeMemTag
SanitizeNumericalStability
SanitizeRealtime
SanitizeRealtimeBlocking
SpeculativeLoadHardening
UWTable(Int)
VScaleRange(Int)
WillReturn
MustProgress
PresplitCoroutine
CoroDestroyOnlyWhenComplete
CoroElideSafe
DenormalFPMath
DenormalFPMathF32
}

impl Eq for FnAttr
impl Hash for FnAttr
impl Show for FnAttr

#
Function

pub struct Function {
uid : UInt64
fty : FunctionType
users : Array[&User]
linkage : Ref[Linkage]
visibility : Ref[Visibility]
unnamed_addr : Ref[UnnamedAddr]
mod : Module
index : Int
addressSpace : AddressSpace
arguments : Array[Argument]
symbols : Map[String, &Value]
attrSet : AttributeSet
basicBlocks : Array[BasicBlock]
// private fields
}

Function of a program.

Developer Note:

  • Function can be &Value, GlobalValue
impl Value for Function
impl Eq for Function
impl Show for Function

#
Function::addAttr

fn Function::addAttr(self : Function, attr : FnAttr) -> Unit

#
Function::addBasicBlock

fn Function::addBasicBlock(self : Function, name? : String, before? : BasicBlock?) -> BasicBlock

#
Function::clearSlot

fn Function::clearSlot(self : Function) -> Unit

#
Function::getArg

fn Function::getArg(self : Function, idx : Int) -> Argument?

#
Function::getDataLayout

fn Function::getDataLayout(self : Function) -> DataLayout

#
Function::getEntryBlock

fn Function::getEntryBlock(self : Function) -> BasicBlock?

#
Function::getFunctionAttrs

fn Function::getFunctionAttrs(self : Function) ->
Set
[FnAttr]

#
Function::getFunctionType

fn Function::getFunctionType(self : Function) -> FunctionType

#
Function::getModule

fn Function::getModule(self : Function) -> Module

#
Function::getNumArgs

fn Function::getNumArgs(self : Function) -> Int

#
Function::getNumBasicBlocks

fn Function::getNumBasicBlocks(self : Function) -> Int

#
Function::getNumParams

fn Function::getNumParams(self : Function) -> Int

#
Function::getParamAttrs

fn Function::getParamAttrs(self : Function, argno : UInt) ->
Set
[ParamAttr]?

#
Function::getParamTypes

fn Function::getParamTypes(self : Function) -> Array[&Type]

#
Function::getReturnAttrs

fn Function::getReturnAttrs(self : Function) ->
Set
[RetAttr]

#
Function::getReturnType

fn Function::getReturnType(self : Function) -> &Type

#
Function::getSlot

fn[V : Value + Show] Function::getSlot(self : Function, val : V) -> UInt64?

#
Function::hasBody

fn Function::hasBody(self : Function) -> Bool

#
Function::instIter

fn Function::instIter(self : Function) -> Iter[&Instruction]

#
Function::isDeclaration

fn Function::isDeclaration(self : Function) -> Bool

#
Function::processSlot

fn Function::processSlot(self : Function) -> Unit

#
Function::removeBasicBlock

fn Function::removeBasicBlock(self : Function, bb : BasicBlock) -> Unit

#
Function::removeUnreachableBlocks

fn Function::removeUnreachableBlocks(self : Function) -> Unit

#
FunctionType

pub struct FunctionType {
ctx : Context
returnType : &Type
paramTypes : Array[&Type]
isVarArg : Bool
}

FunctionType

See LLVM: FunctionType::FunctionType.

test {
let ctx = Context::new()
let int32ty = ctx.getInt32Ty()
let voidty = ctx.getVoidTy()
let f32ty = ctx.getFloatTy()
let f64ty = ctx.getDoubleTy()
let fty = ctx.getFunctionType(voidty, [int32ty, f32ty, f64ty])
inspect(fty, content="void (i32, float, double)")
}
impl Eq for FunctionType

#
FunctionType::getNumParams

fn FunctionType::getNumParams(self : FunctionType) -> Int

Return the number of fixed parameters this function type requires. This does not consider varargs.

  • See LLVM: FunctionType::getNumParams.

#
FunctionType::getParamType

fn FunctionType::getParamType(self : FunctionType, idx : Int) -> &Type?

Get the param type by given index.

#
FunctionType::getParamTypes

fn FunctionType::getParamTypes(self : FunctionType) -> Array[&Type]

Get the params of the function.

  • See LLVM: FunctionType::params.

#
FunctionType::getReturnType

fn FunctionType::getReturnType(self : FunctionType) -> &Type

Get the return type of the function.

#
FunctionType::param_iter

fn FunctionType::param_iter(self : FunctionType) -> Iter[&Type]

Get the iterator of the function parameters.

  • See LLVM: FunctionType::param_begin and FunctionType::param_end.

#
FunctionType::params

fn FunctionType::params(self : FunctionType) -> Array[&Type]

Get the params of the function.

  • See LLVM: FunctionType::params.

#
GetElementPtrInst

pub struct GetElementPtrInst {
uid : UInt64
vty : PointerType
users : Array[&User]
ptr : &Value
indices : Array[&Value]
name : String?
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
isInbounds : Bool
pointeeType : &Type
}

GetElementPtrInst represents a getelementptr instruction that calculates the address of a sub-element of an aggregate object.

Note:

Use IRBuilder::createGEP to create a GetElementPtrInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let array_ty = ctx.getArrayType(i32_ty, 10)
let ptr_ty = ctx.getPtrTy()
let fty = ctx.getFunctionType(ptr_ty, [ptr_ty])
let fval = mod.addFunction(fty, "gep_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
let zero = ctx.getConstInt32(0)
let two = ctx.getConstInt32(2)
builder.setInsertPoint(bb)
let gep = builder.createGEP(
arg,
array_ty,
[zero, two],
name="elem_ptr",
inbounds=true,
)
inspect(
gep,
content=" %elem_ptr = getelementptr inbounds [10 x i32], ptr %0, i32 0, i32 2",
)
assert_true(gep.asValueEnum() is GetElementPtrInst(_))
}

#
GlobalConstant

pub struct GlobalConstant {
uid : UInt64
vty : &Type
elementTy : &Type
users : Array[&User]
mod : Module
name : String
linkage : Ref[Linkage]
visibility : Ref[Visibility]
unnamed_addr : Ref[UnnamedAddr]
value : &Constant
}

#
GlobalConstant::setValue

fn GlobalConstant::setValue(self : GlobalConstant, init : &Constant) -> Unit

#
GlobalValueBase

type GlobalValueBase

#
GlobalValueEnum

pub enum GlobalValueEnum {
Function(Function)
GlobalVariable(GlobalVariable)
GlobalConstant(GlobalConstant)
}

#
GlobalVariable

pub struct GlobalVariable {
uid : UInt64
vty : &Type
elementTy : &Type
users : Array[&User]
mod : Module
name : String
linkage : Ref[Linkage]
visibility : Ref[Visibility]
unnamed_addr : Ref[UnnamedAddr]
initializer : &Constant?
initializerTy : &Type
}

#
GlobalVariable::removeInitializer

fn GlobalVariable::removeInitializer(self : GlobalVariable) -> Unit

#
GlobalVariable::setInitializer

fn GlobalVariable::setInitializer(self : GlobalVariable, init : &Constant) -> Unit

#
HalfType

pub struct HalfType {
ctx : Context
}

impl FPType for HalfType
impl Type for HalfType
impl Eq for HalfType
impl Hash for HalfType
impl Show for HalfType

#
ICmpInst

pub struct ICmpInst {
uid : UInt64
vty : Int1Type
lhs : &Value
rhs : &Value
name : String?
parent : Function
users : Array[&User]
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
predicate : IntPredicate
}

ICmpInst represents an integer comparison instruction that compares two integer values.

Note:

Use IRBuilder::createICmp to create an ICmpInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "icmp_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let eq_cmp = builder.createICmp(EQ, arg1, arg2, name="eq_cmp")
inspect(eq_cmp, content=" %eq_cmp = icmp eq i32 %0, %1")
assert_true(eq_cmp.asValueEnum() is ICmpInst(_))
let ne_cmp = builder.createICmp(NE, arg1, arg2, name="ne_cmp")
inspect(ne_cmp, content=" %ne_cmp = icmp ne i32 %0, %1")
let sgt_cmp = builder.createICmp(SGT, arg1, arg2, name="sgt_cmp")
inspect(sgt_cmp, content=" %sgt_cmp = icmp sgt i32 %0, %1")
let ugt_cmp = builder.createICmp(UGT, arg1, arg2, name="ugt_cmp")
inspect(ugt_cmp, content=" %ugt_cmp = icmp ugt i32 %0, %1")
}
impl User for ICmpInst
impl Value for ICmpInst
impl Show for ICmpInst

#
IRBuilder

pub struct IRBuilder {
ctx : Context
bb : BasicBlock?
insertPt : &Instruction?
}

#
IRBuilder::createAShr

fn IRBuilder::createAShr(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, is_exact? : Bool) -> &Value raise

Create an AShr Instruction

Note:

This creates an arithmetic right shift instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "ashr_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let ashr_result = builder.createAShr(arg1, arg2, name="result")
inspect(ashr_result, content=" %result = ashr i32 %0, %1")
assert_true(ashr_result.asValueEnum() is BinaryInst(_))
let twenty = ctx.getConstInt32(20) // 10100 in binary
let two = ctx.getConstInt32(2) // shift right by 2
let five = builder.createAShr(twenty, two) // 101 in binary = 5
inspect(five, content="i32 5")
assert_true(five.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createAdd

fn IRBuilder::createAdd(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, has_nsw? : Bool, has_nuw? : Bool) -> &Value raise

Create an Add Instruction

Note:

This creates an integer addition instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "add_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let add = builder.createAdd(arg1, arg2, name="sum")
inspect(add, content=" %sum = add i32 %0, %1")
assert_true(add.asValueEnum() is BinaryInst(_))
let one = ctx.getConstInt32(1)
let two = ctx.getConstInt32(2)
let three = builder.createAdd(one, two)
inspect(three, content="i32 3")
assert_true(three.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createAlloca

fn IRBuilder::createAlloca(self : IRBuilder, data_ty : &Type, addressSpace? : AddressSpace, name? : String) -> AllocaInst raise

Create an Alloca Instruction.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let void_ty = ctx.getVoidTy()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(void_ty, [])
let fval = mod.addFunction(fty, "foo")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let inst = builder.createAlloca(i32_ty, name="var1")
inspect(inst, content=" %var1 = alloca i32, align 4")
}

#
IRBuilder::createAnd

fn IRBuilder::createAnd(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an And Instruction

Note:

This creates a bitwise AND instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "and_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let and_result = builder.createAnd(arg1, arg2, name="result")
inspect(and_result, content=" %result = and i32 %0, %1")
assert_true(and_result.asValueEnum() is BinaryInst(_))
let val1 = ctx.getConstInt32(12) // 1100 in binary
let val2 = ctx.getConstInt32(10) // 1010 in binary
let result = builder.createAnd(val1, val2) // 1000 in binary = 8
inspect(result, content="i32 8")
assert_true(result.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createBitCast

fn IRBuilder::createBitCast(self : IRBuilder, src_val : &Value, dst_ty : &PrimitiveType, name? : String) -> &Value raise

Create a BitCast Instruction

Note:

This creates a bitcast instruction that converts a value from one type to another without changing the bit representation. The source and destination types must have the same bit width.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let f32_ty = ctx.getFloatTy()
let fty = ctx.getFunctionType(f32_ty, [i32_ty])
let fval = mod.addFunction(fty, "bitcast_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let bitcast = builder.createBitCast(arg, f32_ty, name="bits")
inspect(bitcast, content=" %bits = bitcast i32 %0 to float")
}

#
IRBuilder::createBr

fn IRBuilder::createBr(self : IRBuilder, dst : BasicBlock) -> &Instruction raise

Create an Unconditional Branch Instruction

Note:

This creates an unconditional branch instruction that transfers control to the specified basic block. The destination must be a valid basic block.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [])
let fval = mod.addFunction(fty, "br_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let target_bb = fval.addBasicBlock(name="target")
builder.setInsertPoint(entry_bb)
let br = builder.createBr(target_bb)
inspect(br, content=" br label %target")
}

#
IRBuilder::createCall

fn IRBuilder::createCall(self : IRBuilder, callee : Function, args : Array[&Value], name? : String) -> CallInst raise

Create a Call Instruction

Note:

This creates a call instruction that invokes a function with the specified arguments. The function must be a valid Function object, and the arguments must match the function's parameter types.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let add_fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let main_fty = ctx.getFunctionType(i32_ty, [])
let add_func = mod.addFunction(add_fty, "add")
let main_func = mod.addFunction(main_fty, "main")
let bb = main_func.addBasicBlock(name="entry")
let arg1 = ctx.getConstInt32(10)
let arg2 = ctx.getConstInt32(20)
builder.setInsertPoint(bb)
let call = builder.createCall(add_func, [arg1, arg2], name="sum")
inspect(call, content=" %sum = call i32 @add(i32 10, i32 20)")
}

#
IRBuilder::createCallPtr

fn IRBuilder::createCallPtr(self : IRBuilder, callee : &Value, functionType : FunctionType, args : Array[&Value], name? : String) -> CallInst raise

#
IRBuilder::createCondBr

fn IRBuilder::createCondBr(self : IRBuilder, cond : &Value, true_dst : BasicBlock, false_dst : BasicBlock) -> &Instruction raise

Create a Conditional Branch Instruction

Note:

This creates a conditional branch instruction that transfers control to one of two basic blocks based on a boolean condition. The condition must be an i1 (boolean) type, and both destinations must be valid basic blocks.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i1_ty = ctx.getInt1Ty()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [i1_ty])
let fval = mod.addFunction(fty, "cond_br_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let true_bb = fval.addBasicBlock(name="true_branch")
let false_bb = fval.addBasicBlock(name="false_branch")
let cond = fval.getArg(0).unwrap()
builder.setInsertPoint(entry_bb)
let cond_br = builder.createCondBr(cond, true_bb, false_bb)
inspect(
cond_br,
content=" br i1 %0, label %true_branch, label %false_branch",
)
}

#
IRBuilder::createExactSDiv

fn IRBuilder::createExactSDiv(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an Exact SDiv Instruction

Note:

This creates an exact signed integer division instruction. Both operands must be integer types with the same bitwidth. The exact flag indicates that the division is expected to be exact (no remainder).

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])

let fval = mod.addFunction(fty, "exact_sdiv_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let div = builder.createExactSDiv(arg1, arg2, name="quotient")
inspect(div, content = " %quotient = sdiv exact i32 %0, %1")
assert_true(div.asValueEnum() is BinaryInst(_))

let twelve = ctx.getConstInt32(12)
let three = ctx.getConstInt32(3)
let four = builder.createExactSDiv(twelve, three)
inspect(four, content = " %2 = sdiv exact i32 12, 3")
assert_true(four.asValueEnum() is ConstantInt(_))

#
IRBuilder::createExactUDiv

fn IRBuilder::createExactUDiv(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an Exact UDiv Instruction

Note:

This creates an exact unsigned integer division instruction. Both operands must be integer types with the same bitwidth. The exact flag indicates that the division is expected to be exact (no remainder).

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])

let fval = mod.addFunction(fty, "exact_udiv_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let div = builder.createExactUDiv(arg1, arg2, name="quotient")
inspect(div, content = " %quotient = udiv exact i32 %0, %1")
assert_true(div.asValueEnum() is BinaryInst(_))

let twelve = ctx.getConstInt32(12)
let three = ctx.getConstInt32(3)
let four = builder.createExactUDiv(twelve, three)
inspect(four, content = " %2 = udiv exact i32 12, 3")
assert_true(four.asValueEnum() is ConstantInt(_))

#
IRBuilder::createExtractValue

fn IRBuilder::createExtractValue(self : IRBuilder, aggregate : &Value, indices : Array[Int], name? : String) -> &Value raise

Create an ExtractValue Instruction

Note:

This creates an extractvalue instruction that extracts a value from an aggregate (struct or array) at the specified index. The aggregate must be an aggregate type, and the index must be valid for the aggregate type.

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let struct_ty = ctx.getStructType([i32_ty, i32_ty])
let fty = ctx.getFunctionType(i32_ty, [struct_ty])

let fval = mod.addFunction(fty, "extractvalue_demo")
let bb = fval.addBasicBlock(name="entry")
let aggregate = fval.getArg(0).unwrap()

builder.setInsertPoint(bb)
let extract = builder.createExtractValue(aggregate, 0, name="field")

inspect(extract, content = " %field = extractvalue { i32, i32 } %0, 0")

#
IRBuilder::createFAdd

fn IRBuilder::createFAdd(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, fast_math? : Array[FastMathFlag]) -> &Value raise

Create an FAdd Instruction

Note:

This creates a floating-point addition instruction. Both operands must be floating-point types with the same bitwidth.

Fast Math Flags:

Allowed Fast Math Flags:
  1. AllowReassoc
  2. AllowContract
  3. NoNaNs
  4. NoInfs
  5. NoSignedZeros
  6. AllowReciprocal
  7. ApproxFunc

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, "fadd_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let fadd = builder.createFAdd(arg1, arg2, name="sum")
inspect(fadd, content = " %sum = fadd float %0, %1")
assert_true(fadd.asValueEnum() is BinaryInst(_))

let one = ctx.getConstFloat(1.0)
let two = ctx.getConstFloat(2.0)
let three = builder.createFAdd(one, two)
inspect(three, content = " %2 = fadd float 0x3FF0000000000000, 0x4000000000000000")
assert_true(three.asValueEnum() is ConstantFP(_))

let nnan_fadd = builder.createFAdd(arg1, arg2, name="sum_nnan", fast_math=[NoNaNs])
inspect(nnan_fadd, content = " %sum_nnan = fadd nnan float %0, %1")

let ninf_fadd = builder.createFAdd(arg1, arg2, name="sum_ninf", fast_math=[NoInfs])
inspect(ninf_fadd, content = " %sum_ninf = fadd ninf float %0, %1")

let nnan_ninf_fadd = builder.createFAdd(
arg1, arg2, name="sum_nnan_ninf", fast_math=[NoNaNs, NoInfs]
)
inspect(nnan_ninf_fadd, content = " %sum_nnan_ninf = fadd nnan ninf float %0, %1")

#
IRBuilder::createFCmp

fn IRBuilder::createFCmp(self : IRBuilder, pred : FloatPredicate, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create a Float Compare Instruction.

Note:

  1. lhs and rhs must be floating-point types with the same bitwidth.
  2. Allowed predicates: OEQ, OGT, OGE, OLT, OLE, ONE, ORD, UEQ, UGT, UGE, ULT, ULE, UNE.

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 arg0 = fval.getArg(0).unwrap()
let arg1 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let oeq_cmp = builder.createFCmp(
FloatPredicate::OEQ,
arg0,
arg1,
name="oeq_cmp",
)
inspect(oeq_cmp, content=" %oeq_cmp = fcmp oeq float %0, %1")
assert_true(oeq_cmp.asValueEnum() is FCmpInst(_))
let val1 = ctx.getConstFloat(3.14)
let val2 = ctx.getConstFloat(3.14)
let result = builder.createFCmpOEQ(val1, val2)
inspect(result, content="i1 true")
assert_true(result.asValueEnum() is ConstantInt(_))
let ogt_cmp = builder.createFCmpOGT(arg0, arg1, name="ogt_cmp")
inspect(ogt_cmp, content=" %ogt_cmp = fcmp ogt float %0, %1")
let oge_cmp = builder.createFCmpOGE(arg0, arg1, name="oge_cmp")
inspect(oge_cmp, content=" %oge_cmp = fcmp oge float %0, %1")
let olt_cmp = builder.createFCmpOLT(arg0, arg1, name="olt_cmp")
inspect(olt_cmp, content=" %olt_cmp = fcmp olt float %0, %1")
let ole_cmp = builder.createFCmpOLE(arg0, arg1, name="ole_cmp")
inspect(ole_cmp, content=" %ole_cmp = fcmp ole float %0, %1")
let one_cmp = builder.createFCmpONE(arg0, arg1, name="one_cmp")
inspect(one_cmp, content=" %one_cmp = fcmp one float %0, %1")
let ord_cmp = builder.createFCmpORD(arg0, arg1, name="ord_cmp")
inspect(ord_cmp, content=" %ord_cmp = fcmp ord float %0, %1")
let ueq_cmp = builder.createFCmpUEQ(arg0, arg1, name="ueq_cmp")
inspect(ueq_cmp, content=" %ueq_cmp = fcmp ueq float %0, %1")
let ugt_cmp = builder.createFCmpUGT(arg0, arg1, name="ugt_cmp")
inspect(ugt_cmp, content=" %ugt_cmp = fcmp ugt float %0, %1")
let uge_cmp = builder.createFCmpUGE(arg0, arg1, name="uge_cmp")
inspect(uge_cmp, content=" %uge_cmp = fcmp uge float %0, %1")
let ult_cmp = builder.createFCmpULT(arg0, arg1, name="ult_cmp")
inspect(ult_cmp, content=" %ult_cmp = fcmp ult float %0, %1")
let ule_cmp = builder.createFCmpULE(arg0, arg1, name="ule_cmp")
inspect(ule_cmp, content=" %ule_cmp = fcmp ule float %0, %1")
let une_cmp = builder.createFCmpUNE(arg0, arg1, name="une_cmp")
inspect(une_cmp, content=" %une_cmp = fcmp une float %0, %1")
}

#
IRBuilder::createFCmpOEQ

fn IRBuilder::createFCmpOEQ(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create OEQ (Ordered Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(OEQ, ...).

#
IRBuilder::createFCmpOGE

fn IRBuilder::createFCmpOGE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create OGE (Ordered Greater Than or Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(OGE, ...).

#
IRBuilder::createFCmpOGT

fn IRBuilder::createFCmpOGT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create OGT (Ordered Greater Than) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(OGT, ...).

#
IRBuilder::createFCmpOLE

fn IRBuilder::createFCmpOLE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create OLE (Ordered Less Than or Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(OLE, ...).

#
IRBuilder::createFCmpOLT

fn IRBuilder::createFCmpOLT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create OLT (Ordered Less Than) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(OLT, ...).

#
IRBuilder::createFCmpONE

fn IRBuilder::createFCmpONE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create ONE (Ordered Not Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(ONE, ...).

#
IRBuilder::createFCmpORD

fn IRBuilder::createFCmpORD(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create ORD (Ordered) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(ORD, ...).

#
IRBuilder::createFCmpUEQ

fn IRBuilder::createFCmpUEQ(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create UEQ (Unordered Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(UEQ, ...).

#
IRBuilder::createFCmpUGE

fn IRBuilder::createFCmpUGE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create UGE (Unordered Greater Than or Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(UGE, ...).

#
IRBuilder::createFCmpUGT

fn IRBuilder::createFCmpUGT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create UGT (Unordered Greater Than) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(UGT, ...).

#
IRBuilder::createFCmpULE

fn IRBuilder::createFCmpULE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create ULE (Unordered Less Than or Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(ULE, ...).

#
IRBuilder::createFCmpULT

fn IRBuilder::createFCmpULT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create ULT (Unordered Less Than) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(ULT, ...).

#
IRBuilder::createFCmpUNE

fn IRBuilder::createFCmpUNE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create UNE (Unordered Not Equal) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(UNE, ...).

#
IRBuilder::createFCmpUNO

fn IRBuilder::createFCmpUNO(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create UNO (Unordered) Comparison Instruction for floating-point values.

It's equivalent to IRBuilder::createFCmp(UNO, ...).

#
IRBuilder::createFDiv

fn IRBuilder::createFDiv(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, fast_math_flags? :
Set
[FastMathFlag]) -> &Value raise

Create an FDiv Instruction

Note:

This creates a floating-point division instruction. Both operands must be floating-point types with the same bitwidth.

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, "fdiv_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let fdiv = builder.createFDiv(arg1, arg2, name="quotient")
inspect(fdiv, content = " %quotient = fdiv float %0, %1")
assert_true(fdiv.asValueEnum() is BinaryInst(_))

let eight = ctx.getConstFloat(8.0)
let two = ctx.getConstFloat(2.0)
let four = builder.createFDiv(eight, two)
inspect(four, content = " %2 = fdiv float 0x4020000000000000, 0x4000000000000000")
assert_true(four.asValueEnum() is ConstantFP(_))

#
IRBuilder::createFMul

fn IRBuilder::createFMul(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, fast_math_flags? :
Set
[FastMathFlag]) -> &Value raise

Create an FMul Instruction

Note:

This creates a floating-point multiplication instruction. Both operands must be floating-point types with the same bitwidth.

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, "fmul_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let fmul = builder.createFMul(arg1, arg2, name="product")
inspect(fmul, content = " %product = fmul float %0, %1")
assert_true(fmul.asValueEnum() is BinaryInst(_))

let three = ctx.getConstFloat(3.0)
let four = ctx.getConstFloat(4.0)
let twelve = builder.createFMul(three, four)
inspect(twelve, content = " %2 = fmul float 0x4008000000000000, 0x4010000000000000")
assert_true(twelve.asValueEnum() is ConstantFP(_))

#
IRBuilder::createFNeg

fn IRBuilder::createFNeg(self : IRBuilder, value : &Value, name? : String, fast_math_flags? :
Set
[FastMathFlag]) -> &Value raise

Create an FNeg Instruction

Note:

This creates a floating-point negation instruction. The operand must be a floating-point type.

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])
let fval = mod.addFunction(fty, "fneg_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let fneg = builder.createFNeg(arg, name="neg_value")
inspect(fneg, content=" %neg_value = fneg float %0")
assert_true(fneg.asValueEnum() is FNegInst(_))
}

#
IRBuilder::createFPExt

fn IRBuilder::createFPExt(self : IRBuilder, src_val : &Value, dst_ty : &FPType, name? : String) -> &Value raise

Create a FPExt Instruction

Note:

This creates a floating-point extension instruction that extends a floating-point value to a larger floating-point type. The input value must be a floating-point type, and the target type must be a larger floating-point type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let f32_ty = ctx.getFloatTy()
let f64_ty = ctx.getDoubleTy()
let fty = ctx.getFunctionType(f64_ty, [f32_ty])
let fval = mod.addFunction(fty, "fpext_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let fpext = builder.createFPExt(arg, f64_ty, name="extended")
inspect(fpext, content=" %extended = fpext float %0 to double")
}

#
IRBuilder::createFPToSI

fn IRBuilder::createFPToSI(self : IRBuilder, src_val : &Value, dst_ty : &IntegerType, name? : String) -> &Value raise

Create a FPToSI Instruction

Note:

This creates a floating-point to signed integer conversion instruction that converts a floating-point value to a signed integer. The input value must be a floating-point type, and the target type must be an integer type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let f32_ty = ctx.getFloatTy()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [f32_ty])
let fval = mod.addFunction(fty, "fptosi_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let fptosi = builder.createFPToSI(arg, i32_ty, name="converted")
inspect(fptosi, content=" %converted = fptosi float %0 to i32")
}

#
IRBuilder::createFPToUI

fn IRBuilder::createFPToUI(self : IRBuilder, src_val : &Value, dst_ty : &IntegerType, name? : String) -> &Value raise

Create a FPToUI Instruction

Note:

This creates a floating-point to unsigned integer conversion instruction that converts a floating-point value to an unsigned integer. The input value must be a floating-point type, and the target type must be an integer type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let f32_ty = ctx.getFloatTy()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [f32_ty])
let fval = mod.addFunction(fty, "fptoui_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let fptoui = builder.createFPToUI(arg, i32_ty, name="converted")
inspect(fptoui, content=" %converted = fptoui float %0 to i32")
assert_true(fptoui.asValueEnum() is CastInst(_))
let float_val = ctx.getConstFloat(3.14)
let int_val = builder.createFPToUI(float_val, i32_ty)
inspect(int_val, content="i32 3")
assert_true(int_val.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createFPTrunc

fn IRBuilder::createFPTrunc(self : IRBuilder, src_val : &Value, dst_ty : &FPType, name? : String) -> &Value raise

Create a FPTrunc Instruction

Note:

This creates a floating-point truncation instruction that truncates a floating-point value to a smaller floating-point type. The input value must be a floating-point type, and the target type must be a smaller floating-point type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let f64_ty = ctx.getDoubleTy()
let f32_ty = ctx.getFloatTy()
let fty = ctx.getFunctionType(f32_ty, [f64_ty])
let fval = mod.addFunction(fty, "fptrunc_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let fptrunc = builder.createFPTrunc(arg, f32_ty, name="truncated")
inspect(fptrunc, content=" %truncated = fptrunc double %0 to float")
assert_true(fptrunc.asValueEnum() is CastInst(_))
let big_val = ctx.getConstDouble(3.14159)
let small_val = builder.createFPTrunc(big_val, f32_ty)
assert_true(small_val.asValueEnum() is ConstantFP(_))
}

#
IRBuilder::createFRem

fn IRBuilder::createFRem(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, fast_math_flags? :
Set
[FastMathFlag]) -> &Value raise

Create an FRem Instruction

Note:

This creates a floating-point remainder instruction. Both operands must be floating-point types with the same bitwidth.

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, "frem_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let frem = builder.createFRem(arg1, arg2, name="remainder")
inspect(frem, content = " %remainder = frem float %0, %1")
assert_true(frem.asValueEnum() is BinaryInst(_))

let five_and_half = ctx.getConstFloat(5.5)
let two = ctx.getConstFloat(2.0)
let one_and_half = builder.createFRem(five_and_half, two)
inspect(one_and_half, content = " %2 = frem float 0x4016000000000000, 0x4000000000000000")
assert_true(one_and_half.asValueEnum() is ConstantFP(_))

#
IRBuilder::createFSub

fn IRBuilder::createFSub(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, fast_math_flags? :
Set
[FastMathFlag]) -> &Value raise

Create an FSub Instruction

Note:

This creates a floating-point subtraction instruction. Both operands must be floating-point types with the same bitwidth.

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, "fsub_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let fsub = builder.createFSub(arg1, arg2, name="diff")
inspect(fsub, content = " %diff = fsub float %0, %1")
assert_true(fsub.asValueEnum() is BinaryInst(_))

let five = ctx.getConstFloat(5.0)
let two = ctx.getConstFloat(2.0)
let three = builder.createFSub(five, two)
inspect(three, content = " %2 = fsub float 0x4014000000000000, 0x4000000000000000")
assert_true(three.asValueEnum() is ConstantFP(_))

#
IRBuilder::createGEP

fn IRBuilder::createGEP(self : IRBuilder, ptr : &Value, pointeeType : &Type, indices : Array[&Value], name? : String, inbounds? : Bool) -> &Value raise

Create a GetElementPtr Instruction

Note:

This creates a getelementptr instruction that calculates the address of a sub-element of an aggregate object. The pointer must be a pointer type, and all indices must be integer values. When inbounds is true, the result is undefined if the computed address is outside the bounds of the allocated object.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let array_ty = ctx.getArrayType(i32_ty, 10)
let ptr_ty = ctx.getPtrTy()
let fty = ctx.getFunctionType(ctx.getPtrTy(), [ptr_ty])
let fval = mod.addFunction(fty, "gep_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
let zero = ctx.getConstInt32(0)
let two = ctx.getConstInt32(2)
builder.setInsertPoint(bb)
let gep = builder.createGEP(
arg,
array_ty,
[zero, two],
name="elem_ptr",
inbounds=true,
)
inspect(
gep,
content=" %elem_ptr = getelementptr inbounds [10 x i32], ptr %0, i32 0, i32 2",
)
}

#
IRBuilder::createGlobalString

fn IRBuilder::createGlobalString(self : IRBuilder, string : String, name? : String) -> GlobalConstant raise

#
IRBuilder::createICmp

fn IRBuilder::createICmp(self : IRBuilder, pred : IntPredicate, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an Integer Compare Instruction.

Note:

  1. lhs and rhs must be integer types with the same bitwidth.
  2. Allowed predicates: EQ, NE, SGT, SGE, SLT, SLE, UGT, UGE, ULT, ULE.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "icmp_demo")
let bb = fval.addBasicBlock(name="entry")
let arg0 = fval.getArg(0).unwrap()
let arg1 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let eq_cmp = builder.createICmp(IntPredicate::EQ, arg0, arg1, name="eq_cmp")
inspect(eq_cmp, content=" %eq_cmp = icmp eq i32 %0, %1")
assert_true(eq_cmp.asValueEnum() is ICmpInst(_))
let val1 = ctx.getConstInt32(5)
let val2 = ctx.getConstInt32(5)
let result = builder.createICmpEQ(val1, val2)
inspect(result, content="i1 true")
assert_true(result.asValueEnum() is ConstantInt(_))
let ne_cmp = builder.createICmpNE(arg0, arg1, name="ne_cmp")
inspect(ne_cmp, content=" %ne_cmp = icmp ne i32 %0, %1")
let sgt_cmp = builder.createICmpSGT(arg0, arg1, name="sgt_cmp")
inspect(sgt_cmp, content=" %sgt_cmp = icmp sgt i32 %0, %1")
let sge_cmp = builder.createICmpSGE(arg0, arg1, name="sge_cmp")
inspect(sge_cmp, content=" %sge_cmp = icmp sge i32 %0, %1")
let slt_cmp = builder.createICmpSLT(arg0, arg1, name="slt_cmp")
inspect(slt_cmp, content=" %slt_cmp = icmp slt i32 %0, %1")
let sle_cmp = builder.createICmpSLE(arg0, arg1, name="sle_cmp")
inspect(sle_cmp, content=" %sle_cmp = icmp sle i32 %0, %1")
let ugt_cmp = builder.createICmpUGT(arg0, arg1, name="ugt_cmp")
inspect(ugt_cmp, content=" %ugt_cmp = icmp ugt i32 %0, %1")
let uge_cmp = builder.createICmpUGE(arg0, arg1, name="uge_cmp")
inspect(uge_cmp, content=" %uge_cmp = icmp uge i32 %0, %1")
let ult_cmp = builder.createICmpULT(arg0, arg1, name="ult_cmp")
inspect(ult_cmp, content=" %ult_cmp = icmp ult i32 %0, %1")
let ule_cmp = builder.createICmpULE(arg0, arg1, name="ule_cmp")
inspect(ule_cmp, content=" %ule_cmp = icmp ule i32 %0, %1")
}

#
IRBuilder::createICmpEQ

fn IRBuilder::createICmpEQ(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create Eq (Equality) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(ICMP_EQ, ...).

#
IRBuilder::createICmpNE

fn IRBuilder::createICmpNE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create Ne (Not Equal) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(ICMP_NE, ...).

#
IRBuilder::createICmpSGE

fn IRBuilder::createICmpSGE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create SGE (Signed Greater Than or Equal) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(SGE, ...).

#
IRBuilder::createICmpSGT

fn IRBuilder::createICmpSGT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create SGT (Signed Greater Than) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(SGT, ...).

#
IRBuilder::createICmpSLE

fn IRBuilder::createICmpSLE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create SLE (Signed Less Than or Equal) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(SLE, ...).

#
IRBuilder::createICmpSLT

fn IRBuilder::createICmpSLT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create SLT (Signed Less Than) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(SLT, ...).

#
IRBuilder::createICmpUGE

fn IRBuilder::createICmpUGE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create UGE (Unsigned Greater Than or Equal) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(UGE, ...).

#
IRBuilder::createICmpUGT

fn IRBuilder::createICmpUGT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create UGT (Unsigned Greater Than) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(UGT, ...).

#
IRBuilder::createICmpULE

fn IRBuilder::createICmpULE(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create ULE (Unsigned Less Than or Equal) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(ULE, ...).

#
IRBuilder::createICmpULT

fn IRBuilder::createICmpULT(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create ULT (Unsigned Less Than) Comparison Instruction.

It's equivalent to IRBuilder::createICmp(ULT, ...).

#
IRBuilder::createInsertValue

fn IRBuilder::createInsertValue(self : IRBuilder, aggregate : &Value, value : &Value, indices : Array[Int], name? : String) -> &Value raise

Create an InsertValue Instruction

Note:

This creates an insertvalue instruction that inserts a value into an aggregate (struct or array) at the specified index. The aggregate must be an aggregate type, and the value type must match the element type at the given index.

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let struct_ty = ctx.getStructType([i32_ty, i32_ty])
let fty = ctx.getFunctionType(struct_ty, [struct_ty, i32_ty])

let fval = mod.addFunction(fty, "insertvalue_demo")
let bb = fval.addBasicBlock(name="entry")
let aggregate = fval.getArg(0).unwrap()
let new_value = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let insert = builder.createInsertValue(aggregate, new_value, 1, name="updated")

inspect(insert, content = " %updated = insertvalue { i32, i32 } %0, i32 %1, 1")

#
IRBuilder::createIntToPtr

fn IRBuilder::createIntToPtr(self : IRBuilder, src_val : &Value, name? : String) -> &Value raise

Create an IntToPtr Instruction

Note:

This creates an integer to pointer conversion instruction that converts an integer value to a pointer. The input value must be an integer type, and the target type must be a pointer type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i64_ty = ctx.getInt64Ty()
let ptr_ty = ctx.getPtrTy()
let fty = ctx.getFunctionType(ptr_ty, [i64_ty])
let fval = mod.addFunction(fty, "inttoptr_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let inttoptr = builder.createIntToPtr(arg, name="ptr")
inspect(inttoptr, content=" %ptr = inttoptr i64 %0 to ptr")
}

#
IRBuilder::createLShr

fn IRBuilder::createLShr(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, is_exact? : Bool) -> &Value raise

Create an LShr Instruction

Note:

This creates a logical right shift instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "lshr_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let lshr_result = builder.createLShr(arg1, arg2, name="result")
inspect(lshr_result, content=" %result = lshr i32 %0, %1")
assert_true(lshr_result.asValueEnum() is BinaryInst(_))
let twenty = ctx.getConstInt32(20) // 10100 in binary
let two = ctx.getConstInt32(2) // shift right by 2
let five = builder.createLShr(twenty, two) // 101 in binary = 5
inspect(five, content="i32 5")
assert_true(five.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createLoad

fn IRBuilder::createLoad(self : IRBuilder, load_ty : &Type, ptr : &Value, isVolatile? : Bool, atomicOrdering? : AtomicOrdering, name? : String) -> &Value raise

Create a Load Instruction

Note:

This loads a value from memory at the specified pointer.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(ctx.getVoidTy(), [])
let fval = mod.addFunction(fty, "load_demo")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let alloca = builder.createAlloca(i32_ty, name="temp")
let load = builder.createLoad(i32_ty, alloca, name="val")
inspect(load, content=" %val = load i32, ptr %temp, align 4")
}

#
IRBuilder::createMul

fn IRBuilder::createMul(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, has_nsw? : Bool, has_nuw? : Bool) -> &Value raise

Create a Mul Instruction

Note:

This creates an integer multiplication instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "mul_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let mul = builder.createMul(arg1, arg2, name="product")
inspect(mul, content=" %product = mul i32 %0, %1")
assert_true(mul.asValueEnum() is BinaryInst(_))
let three = ctx.getConstInt32(3)
let four = ctx.getConstInt32(4)
let twelve = builder.createMul(three, four)
inspect(twelve, content="i32 12")
assert_true(twelve.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createNSWAdd

fn IRBuilder::createNSWAdd(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an NSW Add Instruction

Note:

This creates an integer addition instruction with No Signed Wrap (NSW) flag. If signed overflow occurs, the result is undefined.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "nsw_add_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let add = builder.createNSWAdd(arg1, arg2, name="sum")
inspect(add, content=" %sum = add nsw i32 %0, %1")
assert_true(add.asValueEnum() is BinaryInst(_))
let one = ctx.getConstInt32(1)
let two = ctx.getConstInt32(2)
let three = builder.createNSWAdd(one, two)
inspect(three, content="i32 3")
assert_true(three.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createNSWMul

fn IRBuilder::createNSWMul(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an NSW Mul Instruction

Note:

This creates an integer multiplication instruction with No Signed Wrap (NSW) flag. If signed overflow occurs, the result is undefined.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "nsw_mul_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let mul = builder.createNSWMul(arg1, arg2, name="product")
inspect(mul, content=" %product = mul nsw i32 %0, %1")
assert_true(mul.asValueEnum() is BinaryInst(_))
let three = ctx.getConstInt32(3)
let four = ctx.getConstInt32(4)
let twelve = builder.createNSWMul(three, four)
inspect(twelve, content="i32 12")
assert_true(twelve.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createNSWSub

fn IRBuilder::createNSWSub(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an NSW Sub Instruction

Note:

This creates an integer subtraction instruction with No Signed Wrap (NSW) flag. If signed overflow occurs, the result is undefined.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "nsw_sub_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let sub = builder.createNSWSub(arg1, arg2, name="diff")
inspect(sub, content=" %diff = sub nsw i32 %0, %1")
assert_true(sub.asValueEnum() is BinaryInst(_))
let five = ctx.getConstInt32(5)
let two = ctx.getConstInt32(2)
let three = builder.createNSWSub(five, two)
inspect(three, content="i32 3")
assert_true(three.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createNUWAdd

fn IRBuilder::createNUWAdd(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an NUW Add Instruction

Note:

This creates an integer addition instruction with No Unsigned Wrap (NUW) flag. If unsigned overflow occurs, the result is undefined.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "nuw_add_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let add = builder.createNUWAdd(arg1, arg2, name="sum")
inspect(add, content=" %sum = add nuw i32 %0, %1")
assert_true(add.asValueEnum() is BinaryInst(_))
let one = ctx.getConstInt32(1)
let two = ctx.getConstInt32(2)
let three = builder.createNUWAdd(one, two)
inspect(three, content="i32 3")
assert_true(three.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createNUWMul

fn IRBuilder::createNUWMul(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an NUW Mul Instruction

Note:

This creates an integer multiplication instruction with No Unsigned Wrap (NUW) flag. If unsigned overflow occurs, the result is undefined.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "nuw_mul_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let mul = builder.createNUWMul(arg1, arg2, name="product")
inspect(mul, content=" %product = mul nuw i32 %0, %1")
assert_true(mul.asValueEnum() is BinaryInst(_))
let three = ctx.getConstInt32(3)
let four = ctx.getConstInt32(4)
let twelve = builder.createNUWMul(three, four)
inspect(twelve, content="i32 12")
assert_true(twelve.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createNUWSub

fn IRBuilder::createNUWSub(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an NUW Sub Instruction

Note:

This creates an integer subtraction instruction with No Unsigned Wrap (NUW) flag. If unsigned overflow occurs, the result is undefined.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "nuw_sub_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let sub = builder.createNUWSub(arg1, arg2, name="diff")
inspect(sub, content=" %diff = sub nuw i32 %0, %1")
assert_true(sub.asValueEnum() is BinaryInst(_))
let five = ctx.getConstInt32(5)
let two = ctx.getConstInt32(2)
let three = builder.createNUWSub(five, two)
inspect(three, content="i32 3")
assert_true(three.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createNeg

fn IRBuilder::createNeg(self : IRBuilder, val : &Value, name? : String) -> &Value raise

#
IRBuilder::createNot

fn IRBuilder::createNot(self : IRBuilder, val : &Value, name? : String) -> &Value raise

#
IRBuilder::createOr

fn IRBuilder::createOr(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an Or Instruction

Note:

This creates a bitwise OR instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "or_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let or_result = builder.createOr(arg1, arg2, name="result")
inspect(or_result, content=" %result = or i32 %0, %1")
assert_true(or_result.asValueEnum() is BinaryInst(_))
let val1 = ctx.getConstInt32(12) // 1100 in binary
let val2 = ctx.getConstInt32(10) // 1010 in binary
let result = builder.createOr(val1, val2) // 1110 in binary = 14
inspect(result, content="i32 14")
assert_true(result.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createPHI

fn IRBuilder::createPHI(self : IRBuilder, ty : &Type, name? : String) -> PHINode raise

Create a PHI Instruction

Note:

This creates a PHI node instruction that selects a value based on the predecessor basic block. The type specifies the type of the PHI node's result value. Use PHINode::addIncoming to add incoming values and their corresponding basic blocks.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block_bb = fval.addBasicBlock(name="block")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block_bb)
inspect(phi, content=" %result = phi i32 [ 10, %entry ], [ 20, %block ]")
}

#
IRBuilder::createPtrToInt

fn IRBuilder::createPtrToInt(self : IRBuilder, src_val : &Value, dst_ty : &IntegerType, name? : String) -> &Value raise

Create a PtrToInt Instruction

Note:

This creates a pointer to integer conversion instruction that converts a pointer value to an integer. The input value must be a pointer type, and the target type must be an integer type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i64_ty = ctx.getInt64Ty()
let ptr_ty = ctx.getPtrTy()
let fty = ctx.getFunctionType(i64_ty, [ptr_ty])
let fval = mod.addFunction(fty, "ptrtoint_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let ptrtoint = builder.createPtrToInt(arg, i64_ty, name="int_val")
inspect(ptrtoint, content=" %int_val = ptrtoint ptr %0 to i64")
}

#
IRBuilder::createRet

fn IRBuilder::createRet(self : IRBuilder, retVal : &Value) -> &Instruction raise

Create a Return Instruction

Note:

IRBuilder::createRet could not return void. use IRBuilder::createRetVoid for that purpose.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty])
let fval = mod.addFunction(fty, "direct_ret")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let ret = builder.createRet(arg)
inspect(ret, content=" ret i32 %0")
}

#
IRBuilder::createRetVoid

fn IRBuilder::createRetVoid(self : IRBuilder) -> &Instruction raise

Create a Return Instruction with no return value (void)

Note:

If you want to return a value, use IRBuilder::createRet instead.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [])
let fval = mod.addFunction(fty, "direct_ret")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let ret = builder.createRetVoid()
inspect(ret, content=" ret void")
}

#
IRBuilder::createSDiv

fn IRBuilder::createSDiv(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, is_exact? : Bool) -> &Value raise

Create an SDiv Instruction

Note:

This creates a signed integer division instruction. Both operands must be integer types with the same bitwidth.

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])

let fval = mod.addFunction(fty, "sdiv_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let div = builder.createSDiv(arg1, arg2, name="quotient")
inspect(div, content = " %quotient = sdiv i32 %0, %1")
assert_true(div.asValueEnum() is BinaryInst(_))

let twelve = ctx.getConstInt32(12)
let three = ctx.getConstInt32(3)
let four = builder.createSDiv(twelve, three)
inspect(four, content = " %2 = sdiv i32 12, 3")
assert_true(four.asValueEnum() is ConstantInt(_))

#
IRBuilder::createSExt

fn IRBuilder::createSExt(self : IRBuilder, src_val : &Value, dst_ty : &IntegerType, name? : String) -> &Value raise

Create a SExt Instruction

Note:

This creates a sign extension instruction that extends an integer value to a larger integer type by replicating the sign bit. The input value must be an integer type, and the target type must be a larger integer type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let i64_ty = ctx.getInt64Ty()
let fty = ctx.getFunctionType(i64_ty, [i32_ty])
let fval = mod.addFunction(fty, "sext_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let sext = builder.createSExt(arg, i64_ty, name="extended")
inspect(sext, content=" %extended = sext i32 %0 to i64")
assert_true(sext.asValueEnum() is CastInst(_))
let small_val = ctx.getConstInt32(-42)
let big_val = builder.createSExt(small_val, i64_ty)
inspect(big_val, content="i64 -42")
assert_true(big_val.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createSIToFP

fn IRBuilder::createSIToFP(self : IRBuilder, src_val : &Value, dst_ty : &FPType, name? : String) -> &Value raise

Create a SIToFP Instruction

Note:

This creates a signed integer to floating-point conversion instruction that converts a signed integer value to a floating-point value. The input value must be an integer type, and the target type must be a floating-point type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let f32_ty = ctx.getFloatTy()
let fty = ctx.getFunctionType(f32_ty, [i32_ty])
let fval = mod.addFunction(fty, "sitofp_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let sitofp = builder.createSIToFP(arg, f32_ty, name="converted")
inspect(sitofp, content=" %converted = sitofp i32 %0 to float")
}

#
IRBuilder::createSRem

fn IRBuilder::createSRem(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an SRem Instruction

Note:

This creates a signed integer remainder instruction. Both operands must be integer types with the same bitwidth.

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])

let fval = mod.addFunction(fty, "srem_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let rem = builder.createSRem(arg1, arg2, name="remainder")
inspect(rem, content = " %remainder = srem i32 %0, %1")
assert_true(rem.asValueEnum() is BinaryInst(_))

let thirteen = ctx.getConstInt32(13)
let five = ctx.getConstInt32(5)
let three = builder.createSRem(thirteen, five)
inspect(three, content = " %2 = srem i32 13, 5")
assert_true(three.asValueEnum() is ConstantInt(_))

#
IRBuilder::createSelect

fn IRBuilder::createSelect(self : IRBuilder, condition : &Value, trueValue : &Value, falseValue : &Value, name? : String) -> &Value raise

Create a Select Instruction

Note:

This creates a select instruction that chooses between two values based on a boolean condition. The condition must be an i1 (boolean) type, and both values must have the same type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i1_ty = ctx.getInt1Ty()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i1_ty, i32_ty, i32_ty])
let fval = mod.addFunction(fty, "select_demo")
let bb = fval.addBasicBlock(name="entry")
let cond = fval.getArg(0).unwrap()
let true_val = fval.getArg(1).unwrap()
let false_val = fval.getArg(2).unwrap()
builder.setInsertPoint(bb)
let select = builder.createSelect(cond, true_val, false_val, name="result")
inspect(select, content=" %result = select i1 %0, i32 %1, i32 %2")
}

#
IRBuilder::createShl

fn IRBuilder::createShl(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, has_nsw? : Bool, has_nuw? : Bool) -> &Value raise

Create a Shl Instruction

Note:

This creates a left shift instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "shl_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let shl_result = builder.createShl(arg1, arg2, name="result")
inspect(shl_result, content=" %result = shl i32 %0, %1")
assert_true(shl_result.asValueEnum() is BinaryInst(_))
let val = ctx.getConstInt32(5) // 101 in binary
let shift = ctx.getConstInt32(2) // shift left by 2
let result = builder.createShl(val, shift) // 10100 in binary = 20
inspect(result, content="i32 20")
assert_true(result.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createStore

fn IRBuilder::createStore(self : IRBuilder, value : &Value, ptr : &Value, isVolatile? : Bool, atomicOrdering? : AtomicOrdering) -> StoreInst raise

Create a Store Instruction

Note:

This stores a value into memory at the specified pointer.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(ctx.getVoidTy(), [])
let fval = mod.addFunction(fty, "store_demo")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let alloca = builder.createAlloca(i32_ty, name="temp")
let const_val = ctx.getConstInt32(42)
let store = builder.createStore(const_val, alloca)
inspect(store, content=" store i32 42, ptr %temp, align 4")
}

#
IRBuilder::createSub

fn IRBuilder::createSub(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, has_nsw? : Bool, has_nuw? : Bool) -> &Value raise

Create a Sub Instruction

Note:

This creates an integer subtraction instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "sub_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let sub = builder.createSub(arg1, arg2, name="diff")
inspect(sub, content=" %diff = sub i32 %0, %1")
assert_true(sub.asValueEnum() is BinaryInst(_))
let five = ctx.getConstInt32(5)
let two = ctx.getConstInt32(2)
let three = builder.createSub(five, two)
inspect(three, content="i32 3")
assert_true(three.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createSwitch

fn IRBuilder::createSwitch(self : IRBuilder, cond : &Value, defaultDest : BasicBlock) -> SwitchInst raise

Create a Switch Instruction

Note:

This creates a switch instruction that transfers control to one of many basic blocks based on an integer value. The value must be an integer type, and numCases specifies the expected number of cases. Use SwitchInst::addCase to add individual cases after creation.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [i32_ty])
let fval = mod.addFunction(fty, "switch_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let case1_bb = fval.addBasicBlock(name="case1")
let default_bb = fval.addBasicBlock(name="default")
let value = fval.getArg(0).unwrap()
builder.setInsertPoint(entry_bb)
let switch = builder.createSwitch(value, default_bb)
let case_val = ctx.getConstInt32(42)
switch.addCase(case_val, case1_bb)
let expect =
#| switch i32 %0, label %default [
#| i32 42, label %case1
#| ]
inspect(switch, content=expect)
}

#
IRBuilder::createTrunc

fn IRBuilder::createTrunc(self : IRBuilder, src_val : &Value, dst_ty : &IntegerType, name? : String) -> &Value raise

Create a Trunc Instruction

Note:

This creates a truncation instruction that truncates an integer value to a smaller integer type. The input value must be an integer type, and the target type must be a smaller integer type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i64_ty = ctx.getInt64Ty()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i64_ty])
let fval = mod.addFunction(fty, "trunc_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let trunc = builder.createTrunc(arg, i32_ty, name="truncated")
inspect(trunc, content=" %truncated = trunc i64 %0 to i32")
assert_true(trunc.asValueEnum() is CastInst(_))
let big_val = ctx.getConstInt64(0x123456789L)
let small_val = builder.createTrunc(big_val, i32_ty)
inspect(small_val, content="i32 591751049")
assert_true(small_val.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createUDiv

fn IRBuilder::createUDiv(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String, is_exact? : Bool) -> &Value raise

Create a UDiv Instruction

Note:

This creates an unsigned integer division instruction. Both operands must be integer types with the same bitwidth.

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])

let fval = mod.addFunction(fty, "udiv_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let div = builder.createUDiv(arg1, arg2, name="quotient")
inspect(div, content = " %quotient = udiv i32 %0, %1")
assert_true(div.asValueEnum() is BinaryInst(_))

let twelve = ctx.getConstInt32(12)
let three = ctx.getConstInt32(3)
let four = builder.createUDiv(twelve, three)
inspect(four, content = " %2 = udiv i32 12, 3")
assert_true(four.asValueEnum() is ConstantInt(_))

#
IRBuilder::createUIToFP

fn IRBuilder::createUIToFP(self : IRBuilder, src_val : &Value, dst_ty : &FPType, name? : String) -> &Value raise

Create a UIToFP Instruction

Note:

This creates an unsigned integer to floating-point conversion instruction that converts an unsigned integer value to a floating-point value. The input value must be an integer type, and the target type must be a floating-point type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let f32_ty = ctx.getFloatTy()
let fty = ctx.getFunctionType(f32_ty, [i32_ty])
let fval = mod.addFunction(fty, "uitofp_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let uitofp = builder.createUIToFP(arg, f32_ty, name="converted")
inspect(uitofp, content=" %converted = uitofp i32 %0 to float")
assert_true(uitofp.asValueEnum() is CastInst(_))
let int_val = ctx.getConstInt32(42)
let float_val = builder.createUIToFP(int_val, f32_ty)
assert_true(float_val.asValueEnum() is ConstantFP(_))
}

#
IRBuilder::createURem

fn IRBuilder::createURem(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create a URem Instruction

Note:

This creates an unsigned integer remainder instruction. Both operands must be integer types with the same bitwidth.

let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()

let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])

let fval = mod.addFunction(fty, "urem_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()

builder.setInsertPoint(bb)
let rem = builder.createURem(arg1, arg2, name="remainder")
inspect(rem, content = " %remainder = urem i32 %0, %1")
assert_true(rem.asValueEnum() is BinaryInst(_))

let thirteen = ctx.getConstInt32(13)
let five = ctx.getConstInt32(5)
let three = builder.createURem(thirteen, five)
inspect(three, content = " %2 = urem i32 13, 5")
assert_true(three.asValueEnum() is ConstantInt(_))

#
IRBuilder::createXor

fn IRBuilder::createXor(self : IRBuilder, lhs : &Value, rhs : &Value, name? : String) -> &Value raise

Create an Xor Instruction

Note:

This creates a bitwise XOR instruction. Both operands must be integer types with the same bitwidth.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i32_ty, i32_ty])
let fval = mod.addFunction(fty, "xor_demo")
let bb = fval.addBasicBlock(name="entry")
let arg1 = fval.getArg(0).unwrap()
let arg2 = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let xor_result = builder.createXor(arg1, arg2, name="result")
inspect(xor_result, content=" %result = xor i32 %0, %1")
assert_true(xor_result.asValueEnum() is BinaryInst(_))
let val1 = ctx.getConstInt32(12) // 1100 in binary
let val2 = ctx.getConstInt32(10) // 1010 in binary
let result = builder.createXor(val1, val2) // 0110 in binary = 6
inspect(result, content="i32 6")
assert_true(result.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::createZExt

fn IRBuilder::createZExt(self : IRBuilder, src_val : &Value, dst_ty : &IntegerType, name? : String) -> &Value raise

Create a ZExt Instruction

Note:

This creates a zero extension instruction that extends an integer value to a larger integer type by padding with zeros. The input value must be an integer type, and the target type must be a larger integer type.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let i64_ty = ctx.getInt64Ty()
let fty = ctx.getFunctionType(i64_ty, [i32_ty])
let fval = mod.addFunction(fty, "zext_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let zext = builder.createZExt(arg, i64_ty, name="extended")
inspect(zext, content=" %extended = zext i32 %0 to i64")
assert_true(zext.asValueEnum() is CastInst(_))
let small_val = ctx.getConstInt32(42)
let big_val = builder.createZExt(small_val, i64_ty)
inspect(big_val, content="i64 42")
assert_true(big_val.asValueEnum() is ConstantInt(_))
}

#
IRBuilder::getContext

fn IRBuilder::getContext(self : IRBuilder) -> Context

#
IRBuilder::getInsertBlock

fn IRBuilder::getInsertBlock(self : IRBuilder) -> BasicBlock

#
IRBuilder::getInsertFunction

fn IRBuilder::getInsertFunction(self : IRBuilder) -> Function

#
IRBuilder::getModule

fn IRBuilder::getModule(self : IRBuilder) -> Module

#
IRBuilder::setInsertPoint

fn[T : InsertPoint] IRBuilder::setInsertPoint(self : IRBuilder, insertPt : T) -> Unit

#
InsertValueInst

pub struct InsertValueInst {
uid : UInt64
vty : &Type
users : Array[&User]
aggregate : &Value
insert_val : &Value
name : String?
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
indices : Array[Int]
}

InsertValueInst represents an insertvalue instruction that inserts a value into an aggregate (struct or array) at the specified index.

Note:

Use IRBuilder::createInsertValue to create an InsertValueInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let struct_ty = ctx.getStructType([i32_ty, i32_ty])
let fty = ctx.getFunctionType(struct_ty, [struct_ty, i32_ty])
let fval = mod.addFunction(fty, "insertvalue_demo")
let bb = fval.addBasicBlock(name="entry")
let aggregate = fval.getArg(0).unwrap()
let new_value = fval.getArg(1).unwrap()
builder.setInsertPoint(bb)
let insert = builder.createInsertValue(
aggregate,
new_value,
[1],
name="updated",
)
inspect(insert, content=" %updated = insertvalue { i32, i32 } %0, i32 %1, 1")
assert_true(insert.asValueEnum() is InsertValueInst(_))
}

#
InsertValueInst::getAggregateOperand

fn InsertValueInst::getAggregateOperand(self : InsertValueInst) -> &Value

#
InsertValueInst::getIndices

fn InsertValueInst::getIndices(self : InsertValueInst) -> Array[Int]

#
InsertValueInst::getInsertedValueOperand

fn InsertValueInst::getInsertedValueOperand(self : InsertValueInst) -> &Value

#
InstBase

pub struct InstBase {
// private fields
}

#
InstEnum

pub enum InstEnum {
AllocaInst(AllocaInst)
LoadInst(LoadInst)
ExtractValueInst(ExtractValueInst)
FNegInst(FNegInst)
CastInst(CastInst)
BinaryInst(BinaryInst)
ICmpInst(ICmpInst)
FCmpInst(FCmpInst)
StoreInst(StoreInst)
GetElementPtrInst(GetElementPtrInst)
SelectInst(SelectInst)
InsertValueInst(InsertValueInst)
PHINode(PHINode)
ReturnInst(ReturnInst)
BranchInst(BranchInst)
SwitchInst(SwitchInst)
CallInst(CallInst)
}

#
Int16Array

pub type Int16Array Array[Int16]

impl Eq for Int16Array
impl Hash for Int16Array
impl Show for Int16Array

#
Int16Array::from

fn Int16Array::from(data : Array[Int16]) -> Int16Array

#
Int16Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn Int16Array::inner(self : Int16Array) -> Array[Int16]
Convert newtype to its underlying type, automatically derived.

#
Int16Array::iter

fn Int16Array::iter(self : Int16Array) -> Iter[Int16]

#
Int16Array::length

fn Int16Array::length(self : Int16Array) -> Int

#
Int16Type

pub struct Int16Type {
ctx : Context
}

Int16Type

  • See LLVM: Type::getInt16Ty.

test {
let ctx = Context::new()
inspect(ctx.getInt16Ty(), content="i16")
}
impl Type for Int16Type
impl Eq for Int16Type
impl Hash for Int16Type
impl Show for Int16Type

#
Int16Type::getExtendedType

fn Int16Type::getExtendedType(self : Int16Type) -> Int32Type

#
Int1Type

pub struct Int1Type {
ctx : Context
}

Int1Type

  • See LLVM: Type::getInt1Ty.

test {
let ctx = Context::new()
inspect(ctx.getInt1Ty(), content="i1")
}
impl Type for Int1Type
impl Eq for Int1Type
impl Hash for Int1Type
impl Show for Int1Type

#
Int32Array

pub type Int32Array Array[Int]

impl Eq for Int32Array
impl Hash for Int32Array
impl Show for Int32Array

#
Int32Array::from

fn Int32Array::from(data : Array[Int]) -> Int32Array

#
Int32Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn Int32Array::inner(self : Int32Array) -> Array[Int]
Convert newtype to its underlying type, automatically derived.

#
Int32Array::iter

fn Int32Array::iter(self : Int32Array) -> Iter[Int]

#
Int32Array::length

fn Int32Array::length(self : Int32Array) -> Int

#
Int32Type

pub struct Int32Type {
ctx : Context
}

Int32Type

  • See LLVM: Type::getInt32Ty.

test {
let ctx = Context::new()
inspect(ctx.getInt32Ty(), content="i32")
}
impl Type for Int32Type
impl Eq for Int32Type
impl Hash for Int32Type
impl Show for Int32Type

#
Int32Type::getExtendedType

fn Int32Type::getExtendedType(self : Int32Type) -> Int64Type

#
Int64Array

pub type Int64Array Array[Int64]

impl Eq for Int64Array
impl Hash for Int64Array
impl Show for Int64Array

#
Int64Array::from

fn Int64Array::from(data : Array[Int64]) -> Int64Array

#
Int64Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn Int64Array::inner(self : Int64Array) -> Array[Int64]
Convert newtype to its underlying type, automatically derived.

#
Int64Array::iter

fn Int64Array::iter(self : Int64Array) -> Iter[Int64]

#
Int64Array::length

fn Int64Array::length(self : Int64Array) -> Int

#
Int64Type

pub struct Int64Type {
ctx : Context
}

Int64Type

  • See LLVM: Type::getInt64Ty.

test {
let ctx = Context::new()
inspect(ctx.getInt64Ty(), content="i64")
}
impl Type for Int64Type
impl Eq for Int64Type
impl Hash for Int64Type
impl Show for Int64Type

#
Int8Array

impl Eq for Int8Array
impl Hash for Int8Array
impl Show for Int8Array

#
Int8Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn Int8Array::inner(self : Int8Array) -> Array[
Int8
]
Convert newtype to its underlying type, automatically derived.

#
Int8Array::length

fn Int8Array::length(self : Int8Array) -> Int

#
Int8Type

pub struct Int8Type {
ctx : Context
}

Int8Type

  • See LLVM: Type::getInt8Ty.

test {
let ctx = Context::new()
inspect(ctx.getInt8Ty(), content="i8")
}
impl Type for Int8Type
impl Eq for Int8Type
impl Hash for Int8Type
impl Show for Int8Type

#
Int8Type::getExtendedType

fn Int8Type::getExtendedType(self : Int8Type) -> Int16Type

#
IntPredicate

pub(all) enum IntPredicate {
EQ
NE
UGT
UGE
ULT
ULE
SGT
SGE
SLT
SLE
}

#
IntegerTypeEnum

pub enum IntegerTypeEnum {
Int1Type(Int1Type)
Int8Type(Int8Type)
Int16Type(Int16Type)
Int32Type(Int32Type)
Int64Type(Int64Type)
}

#
IntegerTypeEnum::asIntegerTypeClass

fn IntegerTypeEnum::asIntegerTypeClass(self : IntegerTypeEnum) -> &IntegerType

#
IntegerTypeEnum::asTypeClass

fn IntegerTypeEnum::asTypeClass(self : IntegerTypeEnum) -> &Type

#
IntegerTypeEnum::getBitWidth

fn IntegerTypeEnum::getBitWidth(self : IntegerTypeEnum) -> Int

#
LLVMContextImpl

type LLVMContextImpl

#
LabelType

pub struct LabelType {
ctx : Context
}

LabelTy
impl Type for LabelType
impl Eq for LabelType
impl Hash for LabelType
impl Show for LabelType

#
Linkage

pub(all) enum Linkage {
External
AvailableExternally
LinkOnceAny
LinkOnceODR
WeakAny
WeakODR
Appending
Internal
Private
ExternalWeak
Common
}

impl Show for Linkage

#
LoadInst

pub(all) struct LoadInst {
uid : UInt64
vty : &Type
users : Array[&User]
name : String?
ptr : &Value
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
isVolatile : Bool
atomicOrdering : AtomicOrdering
align : Align
}

LoadInst is an instruction that loads a value from a pointer.

Note:

Use IRBuilder::createLoad to create a LoadInst.

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")
}
impl User for LoadInst
impl Value for LoadInst
impl Show for LoadInst

#
MDNode

pub struct MDNode {
metadata : Array[&Metadata]
}

impl Metadata for MDNode
impl Show for MDNode

#
MDString

pub struct MDString {
str : String
}

impl Show for MDString

#
MetadataEnum

pub enum MetadataEnum {
MDString(MDString)
MDNode(MDNode)
}

#
MetadataType

pub struct MetadataType {
ctx : Context
}

impl Eq for MetadataType

#
Module

pub struct Module {
context : Context
functions : Map[String, Function]
globals : Map[String, &GlobalValue]
global_strings : Map[String, GlobalConstant]
globalstr_count : Int
srcFileName : String
moduleID : String
dataLayout : DataLayout
}

impl Show for Module

#
Module::addFunction

fn Module::addFunction(self : Module, fty : FunctionType, name : String, linkage? : Linkage, visibility? : Visibility, unnamed_addr? : UnnamedAddr, addressSpace? : AddressSpace) -> Function raise LLVMValueError

#
Module::addGlobalConstant

fn Module::addGlobalConstant(self : Module, ty : &Type, name : String, value : &Constant, linkage? : Linkage, visibility? : Visibility, unnamed_addr? : UnnamedAddr) -> GlobalConstant raise LLVMValueError

#
Module::addGlobalString

fn Module::addGlobalString(self : Module, string : String, name? : String) -> GlobalConstant raise

#
Module::addGlobalVariable

fn Module::addGlobalVariable(self : Module, ty : &Type, name : String, initializer? : &Constant, linkage? : Linkage, visibility? : Visibility, unnamed_addr? : UnnamedAddr) -> GlobalVariable raise LLVMValueError

#
Module::dump

fn Module::dump(self : Module) -> Unit

#
Module::getContext

fn Module::getContext(self : Module) -> Context

#
Module::getDataLayout

fn Module::getDataLayout(self : Module) -> DataLayout

#
Module::getFunction

fn Module::getFunction(self : Module, name : String) -> Function?

#
Module::new

fn Module::new(moduleID : String, srcFileName : String, ctx : Context) -> Module

#
NumberArrayEnum

pub enum NumberArrayEnum {
Int8Array(Int8Array)
Int16Array(Int16Array)
Int32Array(Int32Array)
Int64Array(Int64Array)
UInt8Array(UInt8Array)
UInt16Array(UInt16Array)
UInt32Array(UInt32Array)
UInt64Array(UInt64Array)
FloatArray(FloatArray)
DoubleArray(DoubleArray)
}

#
PHINode

pub struct PHINode {
uid : UInt64
vty : &Type
users : Array[&User]
name : String?
incomings : Array[(&Value, BasicBlock)]
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
}

PHINode represents a PHI node instruction that selects a value based on the predecessor basic block.

Note:

Use IRBuilder::createPHI to create a PHINode, then use PHINode::addIncoming to add incoming values.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block_bb = fval.addBasicBlock(name="block")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block_bb)
inspect(phi, content=" %result = phi i32 [ 10, %entry ], [ 20, %block ]")
assert_true(phi.asValueEnum() is PHINode(_))
}
impl User for PHINode
impl Value for PHINode
impl Show for PHINode

#
PHINode::addIncoming

fn PHINode::addIncoming(self : PHINode, value : &Value, block : BasicBlock) -> Unit raise LLVMValueError

Add an incoming value-block pair to the PHI node.

Note:

The value's type must match the PHI node's type. Will raise LLVMValueError if there is a type mismatch. The basic block represents the predecessor block from which this value flows into the PHI node.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_add_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block1_bb = fval.addBasicBlock(name="block1")
let block2_bb = fval.addBasicBlock(name="block2")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
let val3 = ctx.getConstInt32(30)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
inspect(phi.getNumIncomingValues(), content="0")
phi.addIncoming(val1, entry_bb)
inspect(phi.getNumIncomingValues(), content="1")
inspect(phi.getIncomingValue(0).unwrap().getValueRepr(), content="10")
inspect(phi.getIncomingBlock(0).unwrap().getValueRepr(), content="%entry")
phi.addIncoming(val2, block1_bb)
phi.addIncoming(val3, block2_bb)
inspect(phi.getNumIncomingValues(), content="3")
let expected = " %result = phi i32 [ 10, %entry ], [ 20, %block1 ], [ 30, %block2 ]"
inspect(phi, content=expected)
}

#
PHINode::getIncoming

fn PHINode::getIncoming(self : PHINode, idx : Int) -> (&Value, BasicBlock)?

Get the incoming value-block pair at the specified index.

Note:

Returns None if the index is out of bounds. This is a convenience method that returns both the value and block together.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_incoming_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block_bb = fval.addBasicBlock(name="block")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block_bb)
let (value0, block0) = phi.getIncoming(0).unwrap()
inspect(value0.getValueRepr(), content="10")
inspect(block0.getValueRepr(), content="%entry")
let (value1, block1) = phi.getIncoming(1).unwrap()
inspect(value1.getValueRepr(), content="20")
inspect(block1.getValueRepr(), content="%block")
inspect(phi.getIncoming(2), content="None")
}

#
PHINode::getIncomingBlock

fn PHINode::getIncomingBlock(self : PHINode, idx : Int) -> BasicBlock?

Get the incoming basic block at the specified index.

Note:

Returns None if the index is out of bounds. Use PHINode::getNumIncomingValues to get the valid range.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_block_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block_bb = fval.addBasicBlock(name="block")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block_bb)
inspect(phi.getIncomingBlock(0).unwrap().getValueRepr(), content="%entry")
inspect(phi.getIncomingBlock(1).unwrap().getValueRepr(), content="%block")
inspect(phi.getIncomingBlock(2), content="None")
}

#
PHINode::getIncomingBlocks

fn PHINode::getIncomingBlocks(self : PHINode) -> Array[BasicBlock]

Get all incoming basic blocks as an array.

Note:

Returns an array containing only the basic blocks from all incoming value-block pairs, in the order they were added.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_blocks_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block1_bb = fval.addBasicBlock(name="block1")
let block2_bb = fval.addBasicBlock(name="block2")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
let val3 = ctx.getConstInt32(30)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block1_bb)
phi.addIncoming(val3, block2_bb)
let blocks = phi.getIncomingBlocks()
inspect(blocks.length(), content="3")
inspect(blocks[0].getValueRepr(), content="%entry")
inspect(blocks[1].getValueRepr(), content="%block1")
inspect(blocks[2].getValueRepr(), content="%block2")
}

#
PHINode::getIncomingValue

fn PHINode::getIncomingValue(self : PHINode, idx : Int) -> &Value?

Get the incoming value at the specified index.

Note:

Returns None if the index is out of bounds. Use PHINode::getNumIncomingValues to get the valid range.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_value_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block_bb = fval.addBasicBlock(name="block")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block_bb)
inspect(phi.getIncomingValue(0).unwrap().getValueRepr(), content="10")
inspect(phi.getIncomingValue(1).unwrap().getValueRepr(), content="20")
inspect(phi.getIncomingValue(2), content="None")
}

#
PHINode::getIncomingValues

fn PHINode::getIncomingValues(self : PHINode) -> Array[&Value]

Get all incoming values as an array.

Note:

Returns an array containing only the values from all incoming value-block pairs, in the order they were added.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_values_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block1_bb = fval.addBasicBlock(name="block1")
let block2_bb = fval.addBasicBlock(name="block2")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
let val3 = ctx.getConstInt32(30)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block1_bb)
phi.addIncoming(val3, block2_bb)
let values = phi.getIncomingValues()
inspect(values.length(), content="3")
inspect(values[0].getValueRepr(), content="10")
inspect(values[1].getValueRepr(), content="20")
inspect(values[2].getValueRepr(), content="30")
}

#
PHINode::getIncomings

fn PHINode::getIncomings(self : PHINode) -> Array[(&Value, BasicBlock)]

Get all incoming value-block pairs as an array.

Note:

Returns a copy of the internal array containing all value-block pairs in the order they were added.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_incomings_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block1_bb = fval.addBasicBlock(name="block1")
let block2_bb = fval.addBasicBlock(name="block2")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
let val3 = ctx.getConstInt32(30)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
phi.addIncoming(val1, entry_bb)
phi.addIncoming(val2, block1_bb)
phi.addIncoming(val3, block2_bb)
let incomings = phi.getIncomings()
inspect(incomings.length(), content="3")
inspect(incomings[0].0.getValueRepr(), content="10")
inspect(incomings[0].1.getValueRepr(), content="%entry")
inspect(incomings[1].0.getValueRepr(), content="20")
inspect(incomings[2].0.getValueRepr(), content="30")
}

#
PHINode::getNumIncomingValues

fn PHINode::getNumIncomingValues(self : PHINode) -> Int

Get the number of incoming values in the PHI node.

Note:

Returns the total count of incoming value-block pairs added to this PHI node.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [])
let fval = mod.addFunction(fty, "phi_num_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let block1_bb = fval.addBasicBlock(name="block1")
let block2_bb = fval.addBasicBlock(name="block2")
let merge_bb = fval.addBasicBlock(name="merge")
let val1 = ctx.getConstInt32(10)
let val2 = ctx.getConstInt32(20)
let val3 = ctx.getConstInt32(30)
builder.setInsertPoint(merge_bb)
let phi = builder.createPHI(i32_ty, name="result")
inspect(phi.getNumIncomingValues(), content="0")
phi.addIncoming(val1, entry_bb)
inspect(phi.getNumIncomingValues(), content="1")
phi.addIncoming(val2, block1_bb)
phi.addIncoming(val3, block2_bb)
inspect(phi.getNumIncomingValues(), content="3")
}

#
ParamAttr

pub(all) enum ParamAttr {
Alignment(Int)
AllocAlign
AllocatedPointer
ByVal(&Type)
ByRef(&Type)
NoUndef
Dereferenceable(Int)
DereferenceableOrNull(Int)
ElementType(&Type)
InAlloca(&Type)
Initializes
InReg
NoFPClass
Nest
NoAlias
Captures
NoExt
NoFree
DeadOnUnwind
NonNull
Preallocated(&Type)
Range
ReadNone
ReadOnly
Returned
ImmArg
SExt
StackAlignment(Int)
StructRet
SwiftError
SwiftSelf
SwiftAsync
Writable
WriteOnly
ZExt
}

TODO: Initializes is a ConstantRangeListAttr TODO: Range is a ConstantRangeAttr
impl Eq for ParamAttr
impl Hash for ParamAttr
impl Show for ParamAttr

#
PointerType

pub struct PointerType {
ctx : Context
addressSpace : AddressSpace
}

PointerType Note: Before LLVM17, TypedPointer is supported. After LLVM17, all pointer are opaque pointer, and typed pointer is deprecated.

In Moonbit Aether framework, we follow the design of LLVM20, so all pointer is also opaque pointer, and will not mark type for pointer.

test {
let ctx = Context::new()
inspect(ctx.getPtrTy(), content="ptr")
let addressSpace = AddressSpace::new(0)
let ptr = ctx.getPtrTy(addressSpace~)
inspect(ptr, content="ptr")
let i32ty = ctx.getInt32Ty()
assert_true(PointerType::isLoadableOrStorableType(i32ty))
let voidty = ctx.getVoidTy()
assert_false(PointerType::isLoadableOrStorableType(voidty))
}
impl Type for PointerType
impl Eq for PointerType
impl Hash for PointerType
impl Show for PointerType

#
PointerType::getAddressSpace

fn PointerType::getAddressSpace(self : PointerType) -> AddressSpace

#
PointerType::isLoadableOrStorableType

fn PointerType::isLoadableOrStorableType(eleTy : &Type) -> Bool

#
PrimitiveTypeEnum

pub enum PrimitiveTypeEnum {
HalfType(HalfType)
BFloatType(BFloatType)
FloatType(FloatType)
DoubleType(DoubleType)
FP128Type(FP128Type)
Int1Type(Int1Type)
Int8Type(Int8Type)
Int16Type(Int16Type)
Int32Type(Int32Type)
Int64Type(Int64Type)
}

#
PrimitiveTypeEnum::getBitWidth

fn PrimitiveTypeEnum::getBitWidth(self : PrimitiveTypeEnum) -> Int

#
RetAttr

pub(all) enum RetAttr {
Alignment(Int)
NoUndef
Dereferenceable(Int)
DereferenceableOrNull(Int)
InReg
NoFPClass
NoAlias
NoExt
NonNull
SExt
StackAlignment(Int)
ZExt
}

impl Eq for RetAttr
impl Hash for RetAttr
impl Show for RetAttr

#
ReturnInst

pub struct ReturnInst {
uid : UInt64
vty : VoidType
retVal : &Value?
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
}

ReturnInst represents a return instruction that terminates the current function and optionally returns a value.

Note:

Use IRBuilder::createRet or IRBuilder::createRetVoid to create a ReturnInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(i32_ty, [i32_ty])
let fval = mod.addFunction(fty, "return_demo")
let bb = fval.addBasicBlock(name="entry")
let arg = fval.getArg(0).unwrap()
builder.setInsertPoint(bb)
let ret = builder.createRet(arg)
inspect(ret, content=" ret i32 %0")
assert_true(ret.asValueEnum() is ReturnInst(_))
let void_fty = ctx.getFunctionType(void_ty, [])
let void_fval = mod.addFunction(void_fty, "void_return_demo")
let void_bb = void_fval.addBasicBlock(name="entry")
builder.setInsertPoint(void_bb)
let void_ret = builder.createRetVoid()
inspect(void_ret, content=" ret void")
}
impl User for ReturnInst
impl Value for ReturnInst
impl Show for ReturnInst

#
ScalableVectorType

pub struct ScalableVectorType {
ctx : Context
elementType : &Type
elementCount : Int
}

Base class of all SIMD vector types.

  • See LLVM: ScalableVectorType::get.

test {
let ctx = Context::new()
let f32ty = ctx.getFloatTy()
let vecty = ctx.getScalableVectorType(f32ty, 16)
inspect(vecty, content="<vscale x 16 x float>")
assert_eq(vecty.getElementCount(), 16)
inspect(vecty.getElementType(), content="float")
}

#
ScalableVectorType::getElementCount

fn ScalableVectorType::getElementCount(self : ScalableVectorType) -> Int

Get the number of elements in the vector.

#
ScalableVectorType::getElementType

fn ScalableVectorType::getElementType(self : ScalableVectorType) -> &Type

Get the element type of the vector.

#
SelectInst

pub struct SelectInst {
uid : UInt64
users : Array[&User]
vty : &Type
condition : &Value
trueValue : &Value
falseValue : &Value
name : String?
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
}

SelectInst represents a select instruction that chooses between two values based on a boolean condition.

Note:

Use IRBuilder::createSelect to create a SelectInst.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i1_ty = ctx.getInt1Ty()
let i32_ty = ctx.getInt32Ty()
let fty = ctx.getFunctionType(i32_ty, [i1_ty, i32_ty, i32_ty])
let fval = mod.addFunction(fty, "select_demo")
let bb = fval.addBasicBlock(name="entry")
let cond = fval.getArg(0).unwrap()
let true_val = fval.getArg(1).unwrap()
let false_val = fval.getArg(2).unwrap()
builder.setInsertPoint(bb)
let select = builder.createSelect(cond, true_val, false_val, name="result")
inspect(select, content=" %result = select i1 %0, i32 %1, i32 %2")
assert_true(select.asValueEnum() is SelectInst(_))
}
impl User for SelectInst
impl Value for SelectInst
impl Show for SelectInst

#
SelectInst::getCondition

fn SelectInst::getCondition(self : SelectInst) -> &Value

#
SelectInst::getFalseValue

fn SelectInst::getFalseValue(self : SelectInst) -> &Value

#
SelectInst::getTrueValue

fn SelectInst::getTrueValue(self : SelectInst) -> &Value

#
SetSymbolResult

pub enum SetSymbolResult {
Success
EmptyName
InvalidName
DuplicateName(&Value)
}

#
SignedEnum

type SignedEnum

impl Eq for SignedEnum
impl Hash for SignedEnum
impl Show for SignedEnum

#
SlotTracker

type SlotTracker

#
StoreInst

pub struct StoreInst {
uid : UInt64
vty : &Type
value : &Value
ptr : &Value
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
isVolatile : Bool
atomicOrdering : AtomicOrdering
align : Align
}

StoreInst is an instruction that stores a value to a pointer.

Note:

Use IRBuilder::createStore to create a StoreInst.

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 void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [ptr_ty, i32_ty])
let fval = mod.addFunction(fty, "store_an_integer")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let ptr = fval.getArg(0).unwrap()
ptr.setName("arg0")
let value = fval.getArg(1).unwrap()
value.setName("value")
let s = builder.createStore(value, ptr)
inspect(s, content=" store i32 %value, ptr %arg0, align 4")
}
impl User for StoreInst
impl Value for StoreInst
impl Show for StoreInst

#
StoreInst::getPointerOperand

fn StoreInst::getPointerOperand(self : StoreInst) -> &Value

Get the pointer operand of the store instruction.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [])
let fval = mod.addFunction(fty, "store_an_integer")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let alloca = builder.createAlloca(ctx.getInt32Ty(), name="ptr")
let const42 = ctx.getConstInt32(42)
let s = builder.createStore(const42, alloca)
inspect(s.getPointerOperand(), content=" %ptr = alloca i32, align 4")
}

#
StoreInst::getValueOperand

fn StoreInst::getValueOperand(self : StoreInst) -> &Value

Get the value operand of the store instruction.

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 void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [ptr_ty, i32_ty])
let fval = mod.addFunction(fty, "store_an_integer")
let bb = fval.addBasicBlock(name="entry")
builder.setInsertPoint(bb)
let ptr = fval.getArg(0).unwrap()
ptr.setName("arg0")
let val1 = fval.getArg(1).unwrap()
let const_42 = ctx.getConstInt32(42)
let val2 = builder.createNSWAdd(val1, const_42, name="value")
let s = builder.createStore(val2, ptr)
inspect(s.getValueOperand(), content=" %value = add nsw i32 %0, 42")
}

#
StructType

pub struct StructType {
ctx : Context
elements : Array[&Type]
// private fields
}

Struct Type

  • See LLVM: StructType::get.

test {
let ctx = Context::new()
let i8ty = ctx.getInt8Ty()
let i16ty = ctx.getInt16Ty()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let sty = ctx.getStructType([i32ty, f32ty], name="foo")
inspect(sty.full_info(), content="%foo = type { i32, float }")
let sty = ctx.getStructType([i8ty, i16ty], name="bar", isPacked=true)
inspect(sty.full_info(), content="%bar = type <{ i8, i16 }>")
}
impl Type for StructType
impl Eq for StructType
impl Hash for StructType
impl Show for StructType

#
StructType::body_str

fn StructType::body_str(self : StructType) -> String

#
StructType::element_iter

fn StructType::element_iter(self : StructType) -> Iter[&Type]

  • See LLVM: StructType::element_begin and StructType::element_end.

#
StructType::elements

fn StructType::elements(self : StructType) -> Array[&Type]

Get the elements of the struct.

  • See LLVM: StructType::elements.

#
StructType::full_info

fn StructType::full_info(self : StructType) -> String

#
StructType::getIndexedType

fn StructType::getIndexedType(self : StructType, idxs : ArrayView[Int]) -> &Type?

#
StructType::getName

fn StructType::getName(self : StructType) -> String?

Get the name of the struct.

If the struct is literal, return None.

  • See LLVM: StructType::getName.

#
StructType::isLiteral

fn StructType::isLiteral(self : StructType) -> Bool

Check struct is a literal type.

literal type means the struct only has body but has no name.

  • See LLVM: StructType::isLiteral.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let foo = ctx.getStructType([i32ty, f32ty])
let bar = ctx.getStructType([i32ty, f32ty], name="bar")
assert_true(foo.isLiteral())
assert_false(bar.isLiteral())
}

#
StructType::isOpaque

fn StructType::isOpaque(self : StructType) -> Bool

Check struct is a opaque type. Return true if this is a type with an identity that has no body specified yet. These prints as 'opaque' in .ll files.

  • See LLVM: StructType::isOpaque.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let f32ty = ctx.getFloatTy()
let foo = ctx.getStructType([], name="foo")
let bar = ctx.getStructType([i32ty, f32ty], name="bar")
assert_true(foo.isOpaque())
assert_false(bar.isOpaque())
}

#
StructType::isPacked

fn StructType::isPacked(self : StructType) -> Bool

Check if this is a packed struct type.

  • See LLVM: StructType::isPacked.

Packed struct means the struct has no padding between its elements.

#
StructType::isSized

fn StructType::isSized(self : StructType) -> Bool

#
StructType::removeName

fn StructType::removeName(self : StructType) -> Unit

#
StructType::setBody

fn StructType::setBody(self : StructType, elements : Array[&Type], isPacked? : Bool) -> Unit raise LLVMTypeError

Set the body of the struct.

Only Opaque struct can be set body.

  • See LLVM: StructType::setBody.

#
StructType::setName

fn StructType::setName(self : StructType, new_name : String) -> Unit raise LLVMTypeError

Set the name of the struct.

Note:

  • If the new_name is "" (empty string), the struct will be a literal type.
  • If the new_name has same name with old name, nothing will be changed.
  • If context has already have a struct with the given new name, it will raise error.

  • See LLVM: StructType::setName.

#
SwitchInst

pub struct SwitchInst {
uid : UInt64
vty : VoidType
condition : &Value
defaultDest : BasicBlock
cases : Array[(ConstantInt, BasicBlock)]
parent : Function
bb : Ref[BasicBlock?]
prev : Ref[&Instruction?]
next : Ref[&Instruction?]
}

SwitchInst represents a switch instruction that transfers control to one of many basic blocks based on an integer value.

Note:

Use IRBuilder::createSwitch to create a SwitchInst, then use SwitchInst::addCase to add individual cases.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [i32_ty])
let fval = mod.addFunction(fty, "switch_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let case1_bb = fval.addBasicBlock(name="case1")
let case2_bb = fval.addBasicBlock(name="case2")
let default_bb = fval.addBasicBlock(name="default")
let value = fval.getArg(0).unwrap()
builder.setInsertPoint(entry_bb)
let switch = builder.createSwitch(value, default_bb)
let case_val1 = ctx.getConstInt32(1)
let case_val2 = ctx.getConstInt32(2)
switch.addCase(case_val1, case1_bb)
switch.addCase(case_val2, case2_bb)
let expect =
#| switch i32 %0, label %default [
#| i32 1, label %case1
#| i32 2, label %case2
#| ]
inspect(switch, content=expect)
assert_true(switch.asValueEnum() is SwitchInst(_))
}
impl User for SwitchInst
impl Value for SwitchInst
impl Show for SwitchInst

#
SwitchInst::addCase

fn SwitchInst::addCase(self : SwitchInst, cond : ConstantInt, dest : BasicBlock) -> Unit raise LLVMValueError

Add a case to the switch instruction.

Note:

The case condition must be a constant integer with the same type as the switch condition. Will raise LLVMValueError if there is a type mismatch between the case condition and switch condition.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [i32_ty])
let fval = mod.addFunction(fty, "switch_addcase_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let case1_bb = fval.addBasicBlock(name="case1")
let case2_bb = fval.addBasicBlock(name="case2")
let case3_bb = fval.addBasicBlock(name="case3")
let default_bb = fval.addBasicBlock(name="default")
let value = fval.getArg(0).unwrap()
builder.setInsertPoint(entry_bb)
let switch = builder.createSwitch(value, default_bb)

// Add multiple cases
let case_val1 = ctx.getConstInt32(1)
let case_val2 = ctx.getConstInt32(2)
let case_val3 = ctx.getConstInt32(3)
switch.addCase(case_val1, case1_bb)
switch.addCase(case_val2, case2_bb)
switch.addCase(case_val3, case3_bb)
inspect(switch.getNumCases(), content="3")
assert_true(switch.getCase(0).unwrap().0.getValueRepr() == "1")
assert_true(switch.getCase(1).unwrap().0.getValueRepr() == "2")
assert_true(switch.getCase(2).unwrap().0.getValueRepr() == "3")
}

#
SwitchInst::getCase

fn SwitchInst::getCase(self : SwitchInst, idx : Int) -> (ConstantInt, BasicBlock)?

Get a case from the switch instruction by index.

Note:

Returns None if the index is out of bounds. Use SwitchInst::getNumCases to get the total number of cases.

test {
let ctx = Context::new()
let mod = ctx.addModule("demo")
let builder = ctx.createBuilder()
let i32_ty = ctx.getInt32Ty()
let void_ty = ctx.getVoidTy()
let fty = ctx.getFunctionType(void_ty, [i32_ty])
let fval = mod.addFunction(fty, "switch_case_demo")
let entry_bb = fval.addBasicBlock(name="entry")
let case1_bb = fval.addBasicBlock(name="case1")
let case2_bb = fval.addBasicBlock(name="case2")
let default_bb = fval.addBasicBlock(name="default")
let value = fval.getArg(0).unwrap()
builder.setInsertPoint(entry_bb)
let switch = builder.createSwitch(value, default_bb)
let case_val1 = ctx.getConstInt32(1)
let case_val2 = ctx.getConstInt32(2)
switch.addCase(case_val1, case1_bb)
switch.addCase(case_val2, case2_bb)
inspect(switch.getNumCases(), content="2")
inspect(switch.getCase(0).unwrap().0.getValueRepr(), content="1")
inspect(switch.getCase(0).unwrap().1.getValueRepr(), content="%case1")
inspect(switch.getCase(1).unwrap().0.getValueRepr(), content="2")
inspect(switch.getCase(1).unwrap().1.getValueRepr(), content="%case2")
inspect(switch.getCase(2), content="None")
}

#
SwitchInst::getCondition

fn SwitchInst::getCondition(self : SwitchInst) -> &Value

#
SwitchInst::getDefaultDest

fn SwitchInst::getDefaultDest(self : SwitchInst) -> BasicBlock

#
SwitchInst::getNumCases

fn SwitchInst::getNumCases(self : SwitchInst) -> Int

#
TailCallKind

pub(all) enum TailCallKind {
NoTail
Tail
MustTail
}

#
TokenType

pub struct TokenType {
ctx : Context
}

TokenTy
impl Type for TokenType
impl Eq for TokenType
impl Hash for TokenType
impl Show for TokenType

#
TypeEnum

pub enum TypeEnum {
HalfType(HalfType)
BFloatType(BFloatType)
FloatType(FloatType)
DoubleType(DoubleType)
FP128Type(FP128Type)
Int1Type(Int1Type)
Int8Type(Int8Type)
Int16Type(Int16Type)
Int32Type(Int32Type)
Int64Type(Int64Type)
VoidType(VoidType)
LabelType(LabelType)
MetadataType(MetadataType)
TokenType(TokenType)
FunctionType(FunctionType)
StructType(StructType)
ArrayType(ArrayType)
VectorType(VectorType)
ScalableVectorType(ScalableVectorType)
PointerType(PointerType)
}

impl Eq for TypeEnum
impl Hash for TypeEnum
impl Show for TypeEnum

#
TypeEnum::asTypeClass

fn TypeEnum::asTypeClass(self : TypeEnum) -> &Type

#
TypeSize

pub struct TypeSize {
// private fields
}

impl Eq for TypeSize

#
TypeSize::getFixed

fn TypeSize::getFixed(quantity : UInt64) -> TypeSize

#
TypeSize::getFixedValue

fn TypeSize::getFixedValue(self : TypeSize) -> UInt64?

#
TypeSize::getKnownMinValue

fn TypeSize::getKnownMinValue(self : TypeSize) -> UInt64

#
TypeSize::getScalable

fn TypeSize::getScalable(quantity : UInt64) -> TypeSize

#
TypeSize::isFixed

fn TypeSize::isFixed(self : TypeSize) -> Bool

#
TypeSize::isNonZero

fn TypeSize::isNonZero(self : TypeSize) -> Bool

#
TypeSize::isScalable

fn TypeSize::isScalable(self : TypeSize) -> Bool

#
TypeSize::isZero

fn TypeSize::isZero(self : TypeSize) -> Bool

#
UInt16Array

pub type UInt16Array Array[UInt16]

impl Eq for UInt16Array
impl Hash for UInt16Array
impl Show for UInt16Array

#
UInt16Array::from

fn UInt16Array::from(data : Array[UInt16]) -> UInt16Array

#
UInt16Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn UInt16Array::inner(self : UInt16Array) -> Array[UInt16]
Convert newtype to its underlying type, automatically derived.

#
UInt16Array::iter

fn UInt16Array::iter(self : UInt16Array) -> Iter[UInt16]

#
UInt16Array::length

fn UInt16Array::length(self : UInt16Array) -> Int

#
UInt32Array

pub type UInt32Array Array[UInt]

impl Eq for UInt32Array
impl Hash for UInt32Array
impl Show for UInt32Array

#
UInt32Array::from

fn UInt32Array::from(data : Array[UInt]) -> UInt32Array

#
UInt32Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn UInt32Array::inner(self : UInt32Array) -> Array[UInt]
Convert newtype to its underlying type, automatically derived.

#
UInt32Array::iter

fn UInt32Array::iter(self : UInt32Array) -> Iter[UInt]

#
UInt32Array::length

fn UInt32Array::length(self : UInt32Array) -> Int

#
UInt64Array

pub type UInt64Array Array[UInt64]

impl Eq for UInt64Array
impl Hash for UInt64Array
impl Show for UInt64Array

#
UInt64Array::from

fn UInt64Array::from(data : Array[UInt64]) -> UInt64Array

#
UInt64Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn UInt64Array::inner(self : UInt64Array) -> Array[UInt64]
Convert newtype to its underlying type, automatically derived.

#
UInt64Array::iter

fn UInt64Array::iter(self : UInt64Array) -> Iter[UInt64]

#
UInt64Array::length

fn UInt64Array::length(self : UInt64Array) -> Int

#
UInt8Array

impl Eq for UInt8Array
impl Hash for UInt8Array
impl Show for UInt8Array

#
UInt8Array::inner

#deprecated("Use `struct T(A)` to declare a newtype and use `.0` access the underlying type instead.")
fn UInt8Array::inner(self : UInt8Array) -> Array[
UInt8
]
Convert newtype to its underlying type, automatically derived.

#
UInt8Array::length

fn UInt8Array::length(self : UInt8Array) -> Int

#
UnSignedEnum

type UnSignedEnum

impl Eq for UnSignedEnum

#
UnaryInstEnum

pub enum UnaryInstEnum {
AllocaInst(AllocaInst)
LoadInst(LoadInst)
ExtractValueInst(ExtractValueInst)
FNegInst(FNegInst)
CastInst(CastInst)
}

#
UnnamedAddr

pub(all) enum UnnamedAddr {
NoUnnamedAddr
Local
Global
}

impl Show for UnnamedAddr

#
UserBase

type UserBase

impl Eq for UserBase

#
UserEnum

pub enum UserEnum {
LoadInst(LoadInst)
ExtractValueInst(ExtractValueInst)
FNegInst(FNegInst)
CastInst(CastInst)
BinaryInst(BinaryInst)
ICmpInst(ICmpInst)
FCmpInst(FCmpInst)
StoreInst(StoreInst)
GetElementPtrInst(GetElementPtrInst)
SelectInst(SelectInst)
InsertValueInst(InsertValueInst)
PHINode(PHINode)
ReturnInst(ReturnInst)
BranchInst(BranchInst)
SwitchInst(SwitchInst)
CallInst(CallInst)
}

#
UserEnum::asUserClass

fn UserEnum::asUserClass(self : UserEnum) -> &User

#
ValueBase

type ValueBase

  • users: means the values which use this value, all values can get users list from getUsers()
  • uses: means the values used by this value, not all values have uses list. for example, constant values, function arguments, have no uses list.

For example: %2 = add i32 %0, %1

users of %2 : [] uses of %2 : [%0, %1]

users of %0 : [%2] uses of %0 : []

users of %1 : [%2] uses of %1 : []
impl Eq for ValueBase

#
ValueEnum

pub enum ValueEnum {
Function(Function)
GlobalVariable(GlobalVariable)
GlobalConstant(GlobalConstant)
ConstantInt(ConstantInt)
ConstantFP(ConstantFP)
ConstantPointerNull(ConstantPointerNull)
ConstantArray(ConstantArray)
ConstantVector(ConstantVector)
ConstantString(ConstantString)
ConstantStruct(ConstantStruct)
Argument(Argument)
BasicBlock(BasicBlock)
AllocaInst(AllocaInst)
LoadInst(LoadInst)
ExtractValueInst(ExtractValueInst)
FNegInst(FNegInst)
CastInst(CastInst)
BinaryInst(BinaryInst)
ICmpInst(ICmpInst)
FCmpInst(FCmpInst)
StoreInst(StoreInst)
GetElementPtrInst(GetElementPtrInst)
SelectInst(SelectInst)
InsertValueInst(InsertValueInst)
PHINode(PHINode)
ReturnInst(ReturnInst)
BranchInst(BranchInst)
SwitchInst(SwitchInst)
CallInst(CallInst)
}

#
ValueEnum::asValueClass

fn ValueEnum::asValueClass(self : ValueEnum) -> &Value

#
ValueEnum::tryAsConstantEnum

fn ValueEnum::tryAsConstantEnum(self : ValueEnum) -> ConstantEnum?

#
ValueEnum::tryAsInstEnum

fn ValueEnum::tryAsInstEnum(self : ValueEnum) -> InstEnum?

#
ValueEnum::tryAsUserEnum

fn ValueEnum::tryAsUserEnum(self : ValueEnum) -> UserEnum?

#
VectorType

pub struct VectorType {
ctx : Context
elementType : &Type
elementCount : Int
}

Base class of all SIMD vector types.

  • See LLVM: VectorType::get.

test {
let ctx = Context::new()
let i32ty = ctx.getInt32Ty()
let vecty = ctx.getFixedVectorType(i32ty, 16)
inspect(vecty, content="<16 x i32>")
assert_eq(vecty.getElementCount(), 16)
inspect(vecty.getElementType(), content="i32")
}
impl Type for VectorType
impl Eq for VectorType
impl Hash for VectorType
impl Show for VectorType

#
VectorType::getElementCount

fn VectorType::getElementCount(self : VectorType) -> Int

Get the number of elements in the vector.

#
VectorType::getElementType

fn VectorType::getElementType(self : VectorType) -> &Type

Get the element type of the vector.

#
Visibility

pub(all) enum Visibility {
Default
Hidden
Protected
}

impl Show for Visibility

#
VoidType

pub struct VoidType {
ctx : Context
}

VoidType
impl Type for VoidType
impl Eq for VoidType
impl Hash for VoidType
impl Show for VoidType

#
warning_elimination

fn warning_elimination() -> Unit

FIXME: eliminate this function. This is only for eliminate warning.