Inline ARM64 assembly beside the same work in Zag.
asm_beside_zag.zg
# Inline ARM64 assembly beside the same work in Zag (ffi.md, `inline.ASM`). Each `with [ … ]` binds# variables to registers: `->` copies a value in before the block, `<-` stores a register into a new# variable after it, and `<->` does both, keeping the variable's type. Assembly is always a# `no_check` site: the prover cannot see inside it. Runs on aarch64-macos, built by Zomp; the# oracle reads it but cannot run assembly, so it stops at the first block (`.oracle`).# a times b plus c, in one instructionfnmul_add_asm['a':int64,'b':int64,'c':int64]->int64{no_checkinline.ASM{maddx0,x0,x1,x2}with['a'->x0,'b'->x1,'c'->x2,'r'<-x0];return'r';}# how many zero bits before the first 1, counting from the topfnleading_zeros_asm['n':uint64]->uint64{letmut'z':uint64='n';no_checkinline.ASM{clzx0,x0}with['z'<->x0];return'z';}fnleading_zeros_zag['n':uint64]->uint64{letmut'z':uint64=0;letmut'mask':uint64=9223372036854775808;# the top bitwhile'mask'not_equal0and('n'and.bit'mask')equal_to0{change'mask'='mask'shr1;change'z'='z'plus1;}return'z';}MAIN{std::print.useful["6 times 7 plus 3: assembly ",mul_add_asm[6,7,3],", Zag ",6times7plus3,newln];let'xs':list[uint64]=[1,255,65536,9223372036854775808,0];for'n'inlend'xs'{std::print.useful['n'," has ",leading_zeros_asm['n']," leading zeros (Zag: ",leading_zeros_zag['n'],")",newln];}}
Output
6 times 7 plus 3: assembly 45, Zag 45
1 has 63 leading zeros (Zag: 63)
255 has 56 leading zeros (Zag: 56)
65536 has 47 leading zeros (Zag: 47)
9223372036854775808 has 0 leading zeros (Zag: 0)
0 has 64 leading zeros (Zag: 64)
The reference interpreter can’t run this one to the end, as it doesn’t run assembly.