code: def uops_to_llvm_ir(function_name: str, uops: List[UOp]) -> str:
      # all llvm stuff goes into a module
      module = ir.Module(name=__file__)
  
      # extract global buffers
      buf_to_dtype = {
          u.arg: u.dtype for u in uops if u.uop == UOps.DEFINE_GLOBAL
      }
      buf_index = {x: i for i, x in enumerate(buf_to_dtype.keys())}
  
      # create llvm function
      func_dtypes = [
          (dtype_to_llvm_dtype[dtype], dtype)
          for dtype in buf_to_dtype.values()
          if dtype is not None
      ]
      func = ir.Function(
          module,
          ir.FunctionType(
              ir.VoidType(),
              [
                  x.as_pointer() if isinstance(dt, PtrDType) else x
                  for x, dt in func_dtypes
              ],
          ),
          name=function_name,
      )  # noqa: E501
      for a in func.args:
          if a.type.is_pointer:
              a.add_attribute("noalias")
  
      # add the function attribute "no-nans-fp-math"="true", which informs llvm that it allowed to use vectorization optimizations
      func.attributes._known = func.attributes._known.union(
          frozenset(['"no-nans-fp-math"="true"'])
      )
      func.attributes.add('"no-nans-fp-math"="true"')
  
      bb = [ir.IRBuilder(func.append_basic_block("entry"))]
      loop_blocks: List = []
      reduce_phis: List = []
      # TODO: newvar probably shouldn't be optional
      lvars: Dict[Optional[UOp], Any] = {}  # this Any is an llvm type
  
      for bufname, dtype in buf_to_dtype.items():
          if not isinstance(dtype, PtrDType) and dtype == dtypes.int32:
              lvars[bufname] = bb[-1].sext(
                  func.args[buf_index[bufname]], ir.IntType(32)
              )
  
      for u in uops:
          uop, dtype, vin, args = u.uop, u.dtype, u.vin, u.arg
          if uop == UOps.LOOP:
              bb.append(
                  ir.IRBuilder(
                      func.append_basic_block(
                          f"loop_body_{len(loop_blocks)}"
                      )
                  )
              )
              bb[-2].branch(bb[-1]._block)
  
              phis = []
              for rp in reduce_phis:
                  incoming = lvars[rp]
                  lvars[rp] = bb[-1].phi(dtype_to_llvm_dtype[rp.dtype])
                  lvars[rp].add_incoming(incoming, bb[-2]._block)
                  phis.append((rp, lvars[rp]))
  
              lvars[u] = bb[-1].phi(
                  ir.IntType(32), name=f"loop{len(loop_blocks)}"
              )
              lvars[u].add_incoming(lvars[vin[0]], bb[-2]._block)
              loop_blocks.append((bb[-1], phis))
          if uop == UOps.END:
              block, phis = loop_blocks.pop()
              idx_p1 = bb[-1].add(
                  lvars[vin[0]], ir.Constant(ir.IntType(32), 1)
              )
              lvars[vin[0]].add_incoming(idx_p1, bb[-1]._block)
              for n, phi in phis:
                  phi.add_incoming(lvars[n], bb[-1]._block)
              bb.append(
                  ir.IRBuilder(
                      func.append_basic_block(
                          f"loop_exit_{len(loop_blocks)}"
                      )
                  )
              )
              bb[-2].cbranch(
                  bb[-2].icmp_unsigned(
                      "<", idx_p1, lvars[vin[0].vin[1]]
                  ),
                  block._block,
                  bb[-1]._block,
              )
          if uop == UOps.DEFINE_GLOBAL:
              lvars[u] = func.args[buf_index[args]]
          if uop == UOps.DEFINE_ACC:
              lvars[u] = const(args, dtype)
              reduce_phis.append(u)
          if uop == UOps.SPECIAL:
              lvars[u] = lvars[args.expr]
          if uop == UOps.CONST:
              lvars[u] = const(args, dtype)
          if uop == UOps.LOAD:
              assert dtype is not None
              if len(vin) > 2:
                  gate = bb[-1].trunc(lvars[vin[2]], ir.IntType(1))
                  aug_idx = bb[-1].select(
                      gate,
                      lvars[vin[1]],
                      ir.Constant(ir.IntType(32), 0),
                  )
                  val = bb[-1].load(
                      bb[-1].gep(
                          lvars[vin[0]], [aug_idx], inbounds=True
                      )
                  )
                  val = cast(bb, val, vin[0].dtype, dtype)
                  val = bb[-1].select(gate, val, lvars[vin[3]])
              else:
                  val = bb[-1].load(
                      bb[-1].gep(
                          lvars[vin[0]], [lvars[vin[1]]], inbounds=True
                      )
                  )
                  val = cast(bb, val, vin[0].dtype, dtype)
              lvars[u] = val
          if uop == UOps.PHI:
              lvars[u] = lvars[vin[1]]
              # PHI UOps can link to other PHI Uops, backtrace this to DEFINE_ACC
              backward = vin[0]
              while backward.uop == UOps.PHI:
                  backward = backward.vin[0]
              lvars[backward] = lvars[u]
          if uop == UOps.STORE:
              element = cast(
                  bb, lvars[vin[2]], vin[2].dtype, vin[0].dtype
              )
  
              def store_op():
                  bb[-1].store(
                      element,
                      bb[-1].gep(
                          lvars[vin[0]], [lvars[vin[1]]], inbounds=True
                      ),
                  )
  
              if len(vin) > 3:
                  with bb[-1].if_then(
                      bb[-1].trunc(lvars[vin[3]], ir.IntType(1))
                  ):
                      store_op()
              else:
                  store_op()
          if uop == UOps.ALU:
              lvars[u] = code_for_op[args](
                  bb[-1],
                  *[lvars[x] for x in vin]
                  + [
                      dtype
                      if args not in (BinaryOps.CMPLT, BinaryOps.CMPEQ)
                      else vin[0].dtype
                  ],
              )
          if uop == UOps.CAST:
              lvars[u] = cast(
                  bb,
                  lvars[vin[0]],
                  vin[0].dtype,
                  dtype,
                  bitcast=isinstance(args, tuple) and args[1],
              )
  
      bb[-1].ret_void()
      return str(module)
  
file_path: tinygrad/tinygrad/renderer/llvmir.py
imports: from typing import Final, Dict, Callable, Any, List, Optional
  from llvmlite import ir
  from tinygrad.codegen.linearizer import UOps, UOp
  from tinygrad.dtype import DType, PtrDType, dtypes
  from tinygrad.ops import Op, UnaryOps, BinaryOps, TernaryOps
label_desc: Use image node_id 4 for calling a global function with example usage: uops_to_llvm_ir(function_name, uops) and returns: str