"""
This type stub file was generated by pyright.
"""

import contextlib
from collections.abc import Iterable
from typing import Any

from llvmlite.ir.instructions import (
    AllocaInstr,
    Branch,
    CallInstr,
    ConditionalBranch,
    ExtractValue,
    GEPInstr,
    ICMPInstr,
    InsertValue,
    Instruction,
    LoadInstr,
    PhiInstr,
    Ret,
    StoreInstr,
    Unreachable,
)
from llvmlite.ir.module import Module
from llvmlite.ir.types import Type
from llvmlite.ir.values import Block, Function, Value

_CMP_MAP = ...

class IRBuilder:
    def __init__(self, block: Block = ...) -> None: ...
    @property
    def block(self) -> Block:
        """
        The current basic block.
        """
        ...

    basic_block = ...
    @property
    def function(self) -> Function:
        """
        The current function.
        """
        ...

    @property
    def module(self) -> Module:
        """
        The current module.
        """
        ...

    def position_before(self, instr: Instruction) -> None:
        """
        Position immediately before the given instruction.  The current block
        is also changed to the instruction's basic block.
        """
        ...

    def position_after(self, instr: Instruction) -> None:
        """
        Position immediately after the given instruction.  The current block
        is also changed to the instruction's basic block.
        """
        ...

    def position_at_start(self, block):  # -> None:
        """
        Position at the start of the basic *block*.
        """
        ...

    def position_at_end(self, block):  # -> None:
        """
        Position at the end of the basic *block*.
        """
        ...

    def append_basic_block(self, name=...):
        """
        Append a basic block, with the given optional *name*, to the current
        function.  The current block is not changed.  The new block is returned.
        """
        ...

    def _insert(self, instr: Instruction) -> None: ...
    def remove(self, instr):  # -> None:
        """Remove the given instruction."""
        ...

    def _insert(self, instr: Instruction) -> None:
        """Insert an instruction into the current block (internal method)."""
        ...

    @contextlib.contextmanager
    def goto_block(self, block):  # -> Generator[None, Any, None]:
        """
        A context manager which temporarily positions the builder at the end
        of basic block *bb* (but before any terminator).
        """
        ...

    @contextlib.contextmanager
    def goto_entry_block(self):  # -> Generator[None, Any, None]:
        """
        A context manager which temporarily positions the builder at the
        end of the function's entry block.
        """
        ...

    @contextlib.contextmanager
    def if_then(self, pred, likely=...):  # -> Generator[Any, Any, None]:
        """
        A context manager which sets up a conditional basic block based
        on the given predicate (a i1 value).  If the conditional block
        is not explicitly terminated, a branch will be added to the next
        block.
        If *likely* is given, its boolean value indicates whether the
        predicate is likely to be true or not, and metadata is issued
        for LLVM's optimizers to account for that.
        """
        ...

    @contextlib.contextmanager
    def if_else(
        self, pred, likely=...
    ):  # -> Generator[tuple[_GeneratorContextManager[Any, None, None], _GeneratorContextManager[Any, None, None]], Any, None]:
        """
        A context manager which sets up two conditional basic blocks based
        on the given predicate (a i1 value).
        A tuple of context managers is yield'ed.  Each context manager
        acts as a if_then() block.
        *likely* has the same meaning as in if_then().

        Typical use::
            with builder.if_else(pred) as (then, otherwise):
                with then:
                    # emit instructions for when the predicate is true
                with otherwise:
                    # emit instructions for when the predicate is false
        """
        ...

    @_binop("shl")
    def shl(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Left integer shift:
            name = lhs << rhs
        """
        ...

    @_binop("lshr")
    def lshr(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Logical (unsigned) right integer shift:
            name = lhs >> rhs
        """
        ...

    @_binop("ashr")
    def ashr(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Arithmetic (signed) right integer shift:
            name = lhs >> rhs
        """
        ...

    @_binop("add")
    def add(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Integer addition:
            name = lhs + rhs
        """
        ...

    @_binop("fadd")
    def fadd(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Floating-point addition:
            name = lhs + rhs
        """
        ...

    @_binop("sub")
    def sub(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Integer subtraction:
            name = lhs - rhs
        """
        ...

    @_binop("fsub")
    def fsub(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Floating-point subtraction:
            name = lhs - rhs
        """
        ...

    @_binop("mul")
    def mul(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Integer multiplication:
            name = lhs * rhs
        """
        ...

    @_binop("fmul")
    def fmul(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Floating-point multiplication:
            name = lhs * rhs
        """
        ...

    @_binop("udiv")
    def udiv(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Unsigned integer division:
            name = lhs / rhs
        """
        ...

    @_binop("sdiv")
    def sdiv(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Signed integer division:
            name = lhs / rhs
        """
        ...

    @_binop("fdiv")
    def fdiv(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Floating-point division:
            name = lhs / rhs
        """
        ...

    @_binop("urem")
    def urem(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Unsigned integer remainder:
            name = lhs % rhs
        """
        ...

    @_binop("srem")
    def srem(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Signed integer remainder:
            name = lhs % rhs
        """
        ...

    @_binop("frem")
    def frem(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Floating-point remainder:
            name = lhs % rhs
        """
        ...

    @_binop("or")
    def or_(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Bitwise integer OR:
            name = lhs | rhs
        """
        ...

    @_binop("and")
    def and_(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Bitwise integer AND:
            name = lhs & rhs
        """
        ...

    @_binop("xor")
    def xor(self, lhs: Value, rhs: Value, name: str = ...) -> Value:
        """
        Bitwise integer XOR:
            name = lhs ^ rhs
        """
        ...

    @_binop_with_overflow("sadd")
    def sadd_with_overflow(self, lhs, rhs, name=...):  # -> None:
        """
        Signed integer addition with overflow:
            name = {result, overflow bit} = lhs + rhs
        """
        ...

    @_binop_with_overflow("smul")
    def smul_with_overflow(self, lhs, rhs, name=...):  # -> None:
        """
        Signed integer multiplication with overflow:
            name = {result, overflow bit} = lhs * rhs
        """
        ...

    @_binop_with_overflow("ssub")
    def ssub_with_overflow(self, lhs, rhs, name=...):  # -> None:
        """
        Signed integer subtraction with overflow:
            name = {result, overflow bit} = lhs - rhs
        """
        ...

    @_binop_with_overflow("uadd")
    def uadd_with_overflow(self, lhs, rhs, name=...):  # -> None:
        """
        Unsigned integer addition with overflow:
            name = {result, overflow bit} = lhs + rhs
        """
        ...

    @_binop_with_overflow("umul")
    def umul_with_overflow(self, lhs, rhs, name=...):  # -> None:
        """
        Unsigned integer multiplication with overflow:
            name = {result, overflow bit} = lhs * rhs
        """
        ...

    @_binop_with_overflow("usub")
    def usub_with_overflow(self, lhs, rhs, name=...):  # -> None:
        """
        Unsigned integer subtraction with overflow:
            name = {result, overflow bit} = lhs - rhs
        """
        ...

    def not_(self, value, name=...):  # -> None:
        """
        Bitwise integer complement:
            name = ~value
        """
        ...

    def neg(self, value, name=...):  # -> None:
        """
        Integer negative:
            name = -value
        """
        ...

    @_unop("fneg")
    def fneg(
        self, arg: Value, name: str = ..., flags: str | Iterable[str] = ...
    ) -> Value:
        """
        Floating-point negative:
            name = -arg
        """
        ...

    def icmp_signed(
        self, cmpop: str, lhs: Value, rhs: Value, name: str = ...
    ) -> ICMPInstr:
        """
        Signed integer comparison:
            name = lhs <cmpop> rhs

        where cmpop can be '==', '!=', '<', '<=', '>', '>='
        """
        ...

    def icmp_unsigned(
        self, cmpop: str, lhs: Value, rhs: Value, name: str = ...
    ) -> ICMPInstr:
        """
        Unsigned integer (or pointer) comparison:
            name = lhs <cmpop> rhs

        where cmpop can be '==', '!=', '<', '<=', '>', '>='
        """
        ...

    def fcmp_ordered(
        self,
        cmpop: str,
        lhs: Value,
        rhs: Value,
        name: str = ...,
        flags: str | Iterable[str] = ...,
    ) -> Value:
        """
        Floating-point ordered comparison:
            name = lhs <cmpop> rhs

        where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
        """
        ...

    def fcmp_unordered(
        self,
        cmpop: str,
        lhs: Value,
        rhs: Value,
        name: str = ...,
        flags: str | Iterable[str] = ...,
    ) -> Value:
        """
        Floating-point unordered comparison:
            name = lhs <cmpop> rhs

        where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
        """
        ...

    def select(
        self,
        cond: Value,
        lhs: Value,
        rhs: Value,
        name: str = ...,
        flags: str | Iterable[str] = ...,
    ) -> Value:
        """
        Ternary select operator:
            name = cond ? lhs : rhs
        """
        ...

    @_castop("trunc")
    def trunc(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Truncating integer downcast to a smaller type:
            name = (typ) value
        """
        ...

    @_castop("zext")
    def zext(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Zero-extending integer upcast to a larger type:
            name = (typ) value
        """
        ...

    @_castop("sext")
    def sext(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Sign-extending integer upcast to a larger type:
            name = (typ) value
        """
        ...

    @_castop("fptrunc")
    def fptrunc(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Floating-point downcast to a less precise type:
            name = (typ) value
        """
        ...

    @_castop("fpext")
    def fpext(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Floating-point upcast to a more precise type:
            name = (typ) value
        """
        ...

    @_castop("bitcast")
    def bitcast(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Pointer cast to a different pointer type:
            name = (typ) value
        """
        ...

    @_castop("addrspacecast")
    def addrspacecast(self, value, typ, name=...):  # -> None:
        """
        Pointer cast to a different address space:
            name = (typ) value
        """
        ...

    @_castop("fptoui")
    def fptoui(self, value, typ, name=...):  # -> None:
        """
        Convert floating-point to unsigned integer:
            name = (typ) value
        """
        ...

    @_castop("uitofp")
    def uitofp(self, value, typ, name=...):  # -> None:
        """
        Convert unsigned integer to floating-point:
            name = (typ) value
        """
        ...

    @_castop("fptosi")
    def fptosi(self, value, typ, name=...):  # -> None:
        """
        Convert floating-point to signed integer:
            name = (typ) value
        """
        ...

    @_castop("sitofp")
    def sitofp(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Convert signed integer to floating-point:
            name = (typ) value
        """
        ...

    @_castop("ptrtoint")
    def ptrtoint(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Cast pointer to integer:
            name = (typ) value
        """
        ...

    @_castop("inttoptr")
    def inttoptr(self, value: Value, typ: Type, name: str = ...) -> Value:
        """
        Cast integer to pointer:
            name = (typ) value
        """
        ...

    def alloca(
        self, typ: Type, size: Value | int = ..., name: str = ...
    ) -> AllocaInstr:
        """
        Stack-allocate a slot for *size* elements of the given type.
        (default one element)
        """
        ...

    def load(
        self,
        ptr: Value,
        name: str = ...,
        align: int | None = ...,
        typ: Type | None = ...,
    ) -> LoadInstr:
        """
        Load value from pointer, with optional guaranteed alignment:
            name = *ptr
        """
        ...

    def store(self, value: Value, ptr: Value, align: int | None = ...) -> StoreInstr:
        """
        Store value to pointer, with optional guaranteed alignment:
            *ptr = name
        """
        ...

    def load_atomic(
        self, ptr, ordering, align, name=..., typ=...
    ):  # -> LoadAtomicInstr:
        """
        Load value from pointer, with optional guaranteed alignment:
            name = *ptr
        """
        ...

    def store_atomic(self, value, ptr, ordering, align):  # -> StoreAtomicInstr:
        """
        Store value to pointer, with optional guaranteed alignment:
            *ptr = name
        """
        ...

    def switch(self, value, default):  # -> SwitchInstr:
        """
        Create a switch-case with a single *default* target.
        """
        ...

    def branch(self, target: Block) -> Branch:
        """
        Unconditional branch to *target*.
        """
        ...

    def cbranch(self, cond: Value, truebr: Block, falsebr: Block) -> ConditionalBranch:
        """
        Conditional branch to *truebr* if *cond* is true, else to *falsebr*.
        """
        ...

    def branch_indirect(self, addr):  # -> IndirectBranch:
        """
        Indirect branch to target *addr*.
        """
        ...

    def ret_void(self) -> Ret:
        """
        Return from function without a value.
        """
        ...

    def ret(self, value: Value) -> Ret:
        """
        Return from function with the given *value*.
        """
        ...

    def resume(self, landingpad):  # -> Branch:
        """
        Resume an in-flight exception.
        """
        ...

    def call(
        self,
        fn: Value,
        args: list[Value],
        name: str = ...,
        cconv: str | None = ...,
        tail: bool = ...,
        fastmath: str | Iterable[str] = ...,
        attrs: Any = ...,
        arg_attrs: Any = ...,
    ) -> CallInstr:
        """
        Call function *fn* with *args*:
            name = fn(args...)
        """
        ...

    def asm(self, ftype, asm, constraint, args, side_effect, name=...):  # -> CallInstr:
        """
        Inline assembler.
        """
        ...

    def load_reg(self, reg_type, reg_name, name=...):  # -> CallInstr:
        """
        Load a register value into an LLVM value.
          Example: v = load_reg(IntType(32), "eax")
        """
        ...

    def store_reg(self, value, reg_type, reg_name, name=...):  # -> CallInstr:
        """
        Store an LLVM value inside a register
        Example:
          store_reg(Constant(IntType(32), 0xAAAAAAAA), IntType(32), "eax")
        """
        ...

    def invoke(
        self,
        fn,
        args,
        normal_to,
        unwind_to,
        name=...,
        cconv=...,
        fastmath=...,
        attrs=...,
        arg_attrs=...,
    ):  # -> InvokeInstr:
        ...
    def gep(
        self,
        ptr: Value,
        indices: list[Value],
        inbounds: bool = ...,
        name: str = ...,
        source_etype: Type = ...,
    ) -> GEPInstr:
        """
        Compute effective address (getelementptr):
            name = getelementptr ptr, <indices...>
        """
        ...

    def extract_element(self, vector, idx, name=...):  # -> ExtractElement:
        """
        Returns the value at position idx.
        """
        ...

    def insert_element(self, vector, value, idx, name=...):  # -> InsertElement:
        """
        Returns vector with vector[idx] replaced by value.
        The result is undefined if the idx is larger or equal the vector length.
        """
        ...

    def shuffle_vector(self, vector1, vector2, mask, name=...):  # -> ShuffleVector:
        """
        Constructs a permutation of elements from *vector1* and *vector2*.
        Returns a new vector in the same length of *mask*.

        * *vector1* and *vector2* must have the same element type.
        * *mask* must be a constant vector of integer types.
        """
        ...

    def extract_value(
        self, agg: Value, idx: int | list[int], name: str = ...
    ) -> ExtractValue:
        """
        Extract member number *idx* from aggregate.
        """
        ...

    def insert_value(
        self, agg: Value, value: Value, idx: int | list[int], name: str = ...
    ) -> InsertValue:
        """
        Insert *value* into member number *idx* from aggregate.
        """
        ...

    def phi(
        self, typ: Type, name: str = ..., flags: tuple[str, ...] = ...
    ) -> PhiInstr: ...
    def unreachable(self) -> Unreachable: ...
    def atomic_rmw(self, op, ptr, val, ordering, name=...):  # -> AtomicRMW:
        ...
    def cmpxchg(
        self, ptr, cmp, val, ordering, failordering=..., name=...
    ):  # -> CmpXchg:
        """
        Atomic compared-and-set:
            atomic {
                old = *ptr
                success = (old == cmp)
                if (success)
                    *ptr = val
                }
            name = { old, success }

        If failordering is `None`, the value of `ordering` is used.
        """
        ...

    def landingpad(self, typ, name=..., cleanup=...):  # -> LandingPadInstr:
        ...
    def assume(self, cond):  # -> CallInstr:
        """
        Optimizer hint: assume *cond* is always true.
        """
        ...

    def fence(self, ordering, targetscope=..., name=...):  # -> Fence:
        """
        Add a memory barrier, preventing certain reorderings of load and/or
        store accesses with
        respect to other processors and devices.
        """
        ...

    def comment(self, text):  # -> Comment:
        """
        Puts a single-line comment into the generated IR. This will be ignored
        by LLVM, but can be useful for debugging the output of a compiler. Adds
        a comment to the source file.

        * *text* is a string that does not contain new line characters.
        """
        ...

    @_uniop_intrinsic_int("llvm.bswap")
    def bswap(self, cond):  # -> None:
        """
        Used to byte swap integer values with an even number of bytes (positive
        multiple of 16 bits)
        """
        ...

    @_uniop_intrinsic_int("llvm.bitreverse")
    def bitreverse(self, cond):  # -> None:
        """
        Reverse the bitpattern of an integer value; for example 0b10110110
        becomes 0b01101101.
        """
        ...

    @_uniop_intrinsic_int("llvm.ctpop")
    def ctpop(self, cond):  # -> None:
        """
        Counts the number of bits set in a value.
        """
        ...

    @_uniop_intrinsic_with_flag("llvm.ctlz")
    def ctlz(self, cond, flag):  # -> None:
        """
        Counts leading zero bits in *value*. Boolean *flag* indicates whether
        the result is defined for ``0``.
        """
        ...

    @_uniop_intrinsic_with_flag("llvm.cttz")
    def cttz(self, cond, flag):  # -> None:
        """
        Counts trailing zero bits in *value*. Boolean *flag* indicates whether
        the result is defined for ``0``.
        """
        ...

    @_triop_intrinsic("llvm.fma")
    def fma(self, a, b, c):  # -> None:
        """
        Perform the fused multiply-add operation.
        """
        ...

    def convert_from_fp16(self, a, to=..., name=...):  # -> CallInstr:
        """
        Convert from an i16 to the given FP type
        """
        ...

    @_uniop_intrinsic_float("llvm.convert.to.fp16")
    def convert_to_fp16(self, a):  # -> None:
        """
        Convert the given FP number to an i16
        """
        ...
