code: def specialize_to_arm64(fn_nm, asm):
      var_size = 16
      prev_uop: Optional[UOps] = None
      ins = []
      x_regs = ["x" + str(i) for i in reversed(range(12))]
      s_regs = [
          "s" + str(i)
          for i in reversed(range(3, 32))
          if i <= 7 or i >= 16
      ]
      type_to_reg = {
          dtypes.double: "d",
          dtypes.half: "h",
          dtypes.float32: "s",
          dtypes.bool: "w",
          dtypes.int8: "w",
          dtypes.int32: "w",
          dtypes.int64: "x",
          dtypes.uint8: "w",
          dtypes.uint32: "w",
          dtypes.uint64: "x",
      }
      alu = {
          BinaryOps.ADD: "add",
          BinaryOps.SUB: "sub",
          BinaryOps.MUL: "mul",
          BinaryOps.DIV: "div",
          BinaryOps.MAX: "max",
          BinaryOps.MOD: "",
          BinaryOps.CMPLT: "subs",
          UnaryOps.NOOP: "mov",
          UnaryOps.NEG: "neg",
          UnaryOps.SIN: "bl " + get_name("sinf"),
          UnaryOps.LOG2: "bl " + get_name("log2f"),
          UnaryOps.EXP2: "bl " + get_name("exp2f"),
          UnaryOps.SQRT: "bl " + get_name("sqrtf"),
          TernaryOps.MULACC: "madd",
          TernaryOps.WHERE: "fcsel",
      }
  
      def mov_imm(value, reg):
          # Manually move value into reg if value can't fit
          if value.__class__ is not float and abs(value) > abs(65535):
              ins.append(f"movz w15, #{value & 0xffff}")
              ins.append(
                  f"movk w15, #{(value >> 16) & 0xffff}, lsl #16"
              )
              ins.append(f"sxtw {reg}, w15")
          elif reg[0] == "s":
              ins.append(f"movz x15, 0x{float_to_hex(value)[4:]}")
              ins.append(
                  f"movk x15, 0x{float_to_hex(value)[:4]}, lsl #16"
              )
              ins.append("str x15, [sp, 16]")
              ins.append(f"ldr {reg}, [sp, 16]")
          else:
              ins.append(f"mov {reg}, #{value}")
  
      # Get variables intervals
      live_range: Dict[str, List[int]] = {}
      for i, (uop, out, vin, arg) in enumerate(asm):
          for var in [
              v
              for v in [out] + vin
              if v is not None and v.__class__ is not int
          ]:
              live_range[var.nm] = (
                  [i, i]
                  if var.nm not in live_range
                  else [live_range[var.nm][0], i]
              )
  
      mem_vars: Dict[str, int] = {}
      rtor: Dict[str, str] = {}
  
      def allocate_regs(mvars):
          nonlocal var_size
          for v in [
              v
              for v in mvars
              if v is not None
              and v.__class__ is not int
              and v.nm not in rtor
          ]:
              available_regs = (
                  s_regs if dtypes.is_float(v[1]) else x_regs
              )
              # NOTE: Very simple spill, everything that don't fit in regs goes to mem
              if not available_regs:
                  # ARM needs the stack 16-byte aligned
                  var_size += 16
                  available_regs.append(
                      "s0" if dtypes.is_float(out[1]) else "x12"
                  )
                  mem_vars[v.nm] = var_size
              rtor[v.nm] = available_regs.pop()
  
      temp_floats = ["s0", "s1", "s2"]
      temp_ints = ["x12", "x13", "x16"]
      for i, (uop, out, vin, arg) in enumerate(asm):
          # Clear regs out of interval
          for var, reg in list(rtor.items()):
              available_regs = s_regs if reg[0] == "s" else x_regs
              if (
                  var[1] not in "B"
                  and var not in mem_vars
                  and i > live_range[var][1]
              ):
                  available_regs.append(rtor.pop(var))
          # Assign a registers to the variables using live ranges.
          allocate_regs([out] + vin)
          # Assign temp regs to vin and load them before direct use
          for i, v in enumerate(
              [
                  v
                  for v in vin
                  if v.__class__ is not int and v.nm in mem_vars
              ]
          ):
              rtor[v.nm] = (
                  temp_floats[i]
                  if dtypes.is_float(v[1])
                  else temp_ints[i]
              )
              # ARM64 addressing constraints https://devblogs.microsoft.com/oldnewthing/20220728-00/?p=106912
              ins.append(f"mov x15, {mem_vars[v.nm]}")
              ins.append(f"ldr {rtor[v.nm]}, [sp, x15]")
  
          if uop == UOps.SPECIAL:
              if arg.startswith("data"):
                  # data 8 to n into the stack
                  if int(arg[4:]) >= 8:
                      ins.append(
                          f"ldr x15, [x17, #{(int(arg[4:]) - 8) * 8}]"
                      )
                      ins.append(f"mov {rtor[out.nm]}, x15")
              else:
                  ins.append(f"mov {rtor[out.nm]}, #0")
                  ins.append(f"loop_{arg}:")
          elif uop == UOps.CAST:
              if arg == BinaryOps.CMPLT:
                  if rtor[out.nm][0] == "s":
                      mov_imm(0.0, "s0")
                      mov_imm(1.0, "s1")
                      ins.append(f"fcsel {rtor[out.nm]}, s1, s0, lt")
                  if rtor[out.nm][0] == "x":
                      mov_imm(0, "x14")
                      mov_imm(1, "x15")
                      ins.append(f"csel {rtor[out.nm]}, x15, x14, lt")
              else:
                  ins.append(
                      f"sxtw {rtor[out.nm]}, w{rtor[vin[0].nm][1:]}"
                  )
          elif uop == UOps.ALU:
              if len(vin) == 2 and vin[1].__class__ is int:
                  mov_imm(vin[1], "x15")
              if arg == BinaryOps.MUL and out.dtype == dtypes.bool:
                  ins.append(
                      f"ands {','.join('x15' if v.__class__ is int else rtor[v.nm] for v in [out] + vin)}"
                  )
              elif arg == TernaryOps.WHERE:
                  ins.append(
                      f"fcmp {rtor[vin[0].nm]}, #0.0"
                      if rtor[vin[0].nm][0] == "s"
                      else f"cmp {rtor[vin[0].nm]}, #0"
                  )
                  ins.append(
                      f"{alu[arg]} {rtor[out.nm]}, {rtor[vin[1].nm]}, {rtor[vin[2].nm]}, ne"
                  )
              elif arg in [
                  UnaryOps.LOG2,
                  UnaryOps.SIN,
                  UnaryOps.EXP2,
                  UnaryOps.SQRT,
              ]:
                  # NOTE: Not a real instruction, use to emulate a ext call in unicorn
                  if CI:
                      ins.append(
                          f"{alu[arg]} {rtor[out.nm]} {rtor[vin[0].nm]}"
                      )
                  else:
                      save_regs = [
                          k
                          for k in rtor.keys()
                          if k != out.nm and k not in mem_vars
                      ]
                      ins.append(f"sub sp, sp, #{(len(save_regs))*16}")
                      # Save the registers before they are cleared by func call
                      for i, k in enumerate(save_regs, 1):
                          ins.append(f"str {rtor[k]}, [sp, #{16*i}]")
                      ins.append("stp x29, x30, [sp, #0]!")
                      ins.append("mov x29, sp")
                      ins.append(f"fmov s0, {rtor[vin[0].nm]}")
                      ins.append(alu[arg])
                      ins.append(f"fmov {rtor[out.nm]}, s0")
                      ins.append("mov sp, x29")
                      ins.append("ldp x29, x30, [sp], #0")
                      for i, k in enumerate(save_regs, 1):
                          ins.append(f"ldr {rtor[k]}, [sp, #{16*i}]")
                      ins.append(f"add sp, sp, #{len(save_regs)*16}")
              elif arg == BinaryOps.CMPLT:
                  ins.append(
                      f"{alu[arg]} {','.join('x15' if v.__class__ is int else rtor[v.nm] for v in [out] + vin)}"
                      if not dtypes.is_float(vin[0][1])
                      else f"fcmp {rtor[vin[0].nm]}, {rtor[vin[1].nm]}"
                  )
              elif arg == BinaryOps.MOD:
                  rhs = (
                      "x15"
                      if vin[1].__class__ is int
                      else rtor[vin[1].nm]
                  )
                  ins.append(f"udiv x14, {rtor[vin[0].nm]}, {rhs}")
                  ins.append(
                      f"msub {rtor[out.nm]}, x14, {rhs}, {rtor[vin[0].nm]}"
                  )
              else:
                  ins.append(
                      f"{'f' if dtypes.is_float(vin[0][1]) else 's' if arg == BinaryOps.DIV else ''}{alu[arg]} {', '.join('x15' if v.__class__ is int else rtor[v.nm] for v in [out] + vin)}"
                  )
          elif uop == UOps.LOAD:
              if arg.__class__ in (int, float):
                  mov_imm(arg, rtor[out.nm])
              else:
                  # NOTE: if need casting load var in s/h0 or x/w12 temp regs
                  reg_in = (
                      type_to_reg[arg[2]]
                      + ("0" if dtypes.is_float(arg[2]) else "12")
                      if arg[2] is not None
                      else rtor[out.nm]
                  )
                  mov_imm(arg[0], "x15")
                  ins.append(f"add x15, {rtor[vin[0].nm]}, x15")
                  ins.append(
                      f"ldr{'sb' if arg[2] is not None and arg[2] in (dtypes.int8, dtypes.uint8, dtypes.bool) else ''} {reg_in}, [x15]"
                  )
                  if arg[2] is not None:
                      ins.append(
                          f"{'fcvt' if arg[2] in [dtypes.half, dtypes.double] else 'scvtf'} {rtor[out.nm]}, {reg_in}"
                      )
          elif uop == UOps.STORE:
              # NOTE: if need casting load var in s/h0 or x/w12 temp regs
              reg_out = (
                  type_to_reg[arg[2]]
                  + ("0" if dtypes.is_float(arg[2]) else "12")
                  if arg[2] is not None
                  else rtor[vin[1].nm]
              )
              if arg[2] is not None:
                  ins.append(
                      f"fcvt{'zs' if arg[2] not in [dtypes.half, dtypes.double] else '' } {reg_out}, {rtor[vin[1].nm]}"
                  )
              ins.append(f"mov x15, #{arg[0]}")
              ins.append(
                  f"str {reg_out}, [{rtor[vin[0].nm]}, x15, lsl #0]"
              )
          elif uop == UOps.COND_BRANCH:
              # TODO: this is a hack it shouldn't always be a cmp before a cond branch?
              if prev_uop == UOps.LOAD:
                  ins.append(f"cmp {rtor[vin[0].nm]}, #0")
              ins.append(f"b.{'lt' if arg[1] else 'ge'} {arg[0][1:]}")
          elif uop == UOps.LABEL:
              ins.append(f"{arg[1:]}:")
          elif uop == UOps.ENDLOOP:
              mov_imm(arg[0], "x15")
              ins.append(
                  f"add {rtor[vin[0].nm]}, {rtor[vin[0].nm]}, #1"
              )
              ins.append(f"cmp {rtor[vin[0].nm]}, x15")
              ins.append(f"b.lt loop_{arg[1]}")
          prev_uop = uop
          # store regs into memory if needed
          if out is not None and out.nm in mem_vars:
              ins.append(f"mov x15, {mem_vars[out.nm]}")
              ins.append(f"str {rtor[out.nm]}, [sp, x15]")
      return "\n".join(
          [
              f"//varsize {var_size}",
              ".arch armv8-a",
              ".text",
              f".global {get_name(fn_nm)}",
              ".p2align 2",
              f"{get_name(fn_nm)}:",
              "mov x17, sp",
          ]
          + [
              f"sub sp, sp, #{offset}"
              for offset in compute_offsets(var_size)
          ]
          + ins
          + [
              f"add sp, sp, #{offset}"
              for offset in compute_offsets(var_size)
          ]
          + ["ret", "\n"]
      )
  
file_path: tinygrad/extra/assembly/assembly_arm64.py
imports: import struct
  from platform import system
  from typing import Tuple, Dict, List, Optional
  from tinygrad import dtypes
  from tinygrad.ops import BinaryOps, UnaryOps, TernaryOps
  from tinygrad.codegen.linearizer import UOps, UOp
  from tinygrad.helpers import CI
  from tinygrad.codegen.assembly import uops_to_asmstyle, AssemblyLanguage
label_desc: Use image node_id 4 for calling a global function with example usage: specialize_to_arm64(fn_nm, asm) and returns: str